2003-10-15 sowmini.varadhan@sun.com
* ripd/ripd.c: (rip_send_packet) use rip->sock for mcast sends,
instead of creating one socket per send. send source addr to
rip_update_interface.
(rip_update_process) should send an update on every connected
network for each interface.
(rip_request_send) should send a request on every connected
network for each interface.
* ripd/ripd.h: update prototype for rip_interface_multicast_set
* ripd/rip_interface.c: (rip_interface_multicast_set) reorganized
so that it can be called repeatedly for aliased interfaces (on
multiple networks).
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
index 2668e7d..e3aea18 100644
--- a/ripd/rip_interface.c
+++ b/ripd/rip_interface.c
@@ -137,28 +137,25 @@
}
void
-rip_interface_multicast_set (int sock, struct interface *ifp)
+rip_interface_multicast_set (int sock, struct connected *connected,
+ int if_pointopoint)
{
int ret;
- listnode node;
struct servent *sp;
struct sockaddr_in from;
-
- for (node = listhead (ifp->connected); node; nextnode (node))
- {
- struct prefix_ipv4 *p;
- struct connected *connected;
struct in_addr addr;
+ struct prefix_ipv4 *p;
- connected = getdata (node);
+ if (if_pointopoint)
+ p = (struct prefix_ipv4 *) connected->destination;
+ else
p = (struct prefix_ipv4 *) connected->address;
- if (p->family == AF_INET)
- {
addr = p->prefix;
+
if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
- addr, 0, ifp->ifindex) < 0)
+ addr, 0, 0) < 0)
{
zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
return;
@@ -176,6 +173,7 @@
/* Address shoud be any address. */
from.sin_family = AF_INET;
+ addr = ((struct prefix_ipv4 *) connected->address)->prefix;
from.sin_addr = addr;
#ifdef HAVE_SIN_LEN
from.sin_len = sizeof (struct sockaddr_in);
@@ -184,12 +182,11 @@
if (ripd_privs.change (ZPRIVS_RAISE))
zlog_err ("rip_interface_multicast_set: could not raise privs");
- ret = bind (sock, (struct sockaddr *) & from,
- sizeof (struct sockaddr_in));
+ bind (sock, NULL, 0); /* unbind any previous association */
+ ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
if (ret < 0)
{
zlog_warn ("Can't bind socket: %s", strerror (errno));
- return;
}
if (ripd_privs.change (ZPRIVS_LOWER))
@@ -198,8 +195,6 @@
return;
}
- }
-}
/* Send RIP request packet to specified interface. */
void
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 68f49ac..accac5e 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -60,7 +60,8 @@
void rip_event (enum rip_event, int);
void rip_output_process (struct interface *, struct prefix *,
- struct sockaddr_in *, int, u_char);
+ struct sockaddr_in *, int, u_char,
+ struct prefix_ipv4 *);
/* RIP output routes type. */
enum
@@ -1238,7 +1239,6 @@
{
int ret;
struct sockaddr_in sin;
- int sock;
/* Make destination address. */
memset (&sin, 0, sizeof (struct sockaddr_in));
@@ -1250,39 +1250,29 @@
/* When destination is specified, use it's port and address. */
if (to)
{
- sock = rip->sock;
-
sin.sin_port = to->sin_port;
sin.sin_addr = to->sin_addr;
}
else
{
- sock = socket (AF_INET, SOCK_DGRAM, 0);
-
- sockopt_broadcast (sock);
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
sin.sin_port = htons (RIP_PORT_DEFAULT);
sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
- /* Set multicast interface. */
- rip_interface_multicast_set (sock, ifp);
+ /* caller has set multicast interface */
+
}
- ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin,
+ ret = sendto (rip->sock, buf, size, 0, (struct sockaddr *)&sin,
sizeof (struct sockaddr_in));
if (IS_RIP_DEBUG_EVENT)
- zlog_info ("SEND to socket %d port %d addr %s",
- sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr));
+ zlog_info ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
+ ntohs (sin.sin_port));
if (ret < 0)
zlog_warn ("can't send packet : %s", strerror (errno));
- if (! to)
- close (sock);
-
return ret;
}
@@ -1454,8 +1444,19 @@
ntohs (rte->family) == 0 &&
ntohl (rte->metric) == RIP_METRIC_INFINITY)
{
+ struct prefix_ipv4 saddr;
+
+ /* saddr will be used for determining which routes to split-horizon.
+ Since the source address we'll pick will be on the same subnet as the
+ destination, for the purpose of split-horizoning, we'll
+ pretend that "from" is our source address. */
+ saddr.family = AF_INET;
+ saddr.prefixlen = IPV4_MAX_BITLEN;
+ saddr.prefix = from->sin_addr;
+
/* All route with split horizon */
- rip_output_process (ifp, NULL, from, rip_all_route, packet->version);
+ rip_output_process (ifp, NULL, from, rip_all_route, packet->version,
+ &saddr);
}
else
{
@@ -1979,7 +1980,8 @@
/* Send update to the ifp or spcified neighbor. */
void
rip_output_process (struct interface *ifp, struct prefix *ifaddr,
- struct sockaddr_in *to, int route_type, u_char version)
+ struct sockaddr_in *to, int route_type, u_char version,
+ struct prefix_ipv4 *saddr)
{
int ret;
struct stream *s;
@@ -2118,7 +2120,7 @@
/* We perform split horizon for RIP and connected route. */
if ((rinfo->type == ZEBRA_ROUTE_RIP ||
rinfo->type == ZEBRA_ROUTE_CONNECT) &&
- rinfo->ifindex == ifp->ifindex)
+ prefix_match((struct prefix *)p, (struct prefix *)saddr))
continue;
}
@@ -2247,7 +2249,8 @@
/* Send RIP packet to the interface. */
void
-rip_update_interface (struct interface *ifp, u_char version, int route_type)
+rip_update_interface (struct interface *ifp, u_char version, int route_type,
+ struct prefix_ipv4 *saddr)
{
struct prefix_ipv4 *p;
struct connected *connected;
@@ -2260,7 +2263,8 @@
if (IS_RIP_DEBUG_EVENT)
zlog_info ("multicast announce on %s ", ifp->name);
- rip_output_process (ifp, NULL, NULL, route_type, rip->version_send);
+ rip_output_process (ifp, NULL, NULL, route_type, rip->version_send,
+ saddr);
return;
}
@@ -2288,7 +2292,7 @@
inet_ntoa (to.sin_addr), ifp->name);
rip_output_process (ifp, connected->address, &to, route_type,
- rip->version_send);
+ rip->version_send, saddr);
}
}
}
@@ -2298,7 +2302,8 @@
void
rip_update_process (int route_type)
{
- listnode node;
+ listnode node, ifnode;
+ struct connected *connected;
struct interface *ifp;
struct rip_interface *ri;
struct route_node *rp;
@@ -2336,15 +2341,29 @@
ifp->ifindex);
}
+ /* send update on each connected network */
+
+ 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 vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
rip->version_send : ri->ri_send);
+
+ ifaddr = (struct prefix_ipv4 *) connected->address;
+
+ 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);
+ rip_update_interface (ifp, RIPv1, route_type, ifaddr);
if (vsend & RIPv2)
- rip_update_interface (ifp, RIPv2, route_type);
+ rip_update_interface (ifp, RIPv2, route_type, ifaddr);
}
}
}
@@ -2369,7 +2388,7 @@
to.sin_port = htons (RIP_PORT_DEFAULT);
/* RIP version is rip's configuration. */
- rip_output_process (ifp, NULL, &to, route_type, rip->version_send);
+ rip_output_process (ifp, NULL, &to, route_type, rip->version_send, p);
}
}
@@ -2549,6 +2568,8 @@
{
struct rte *rte;
struct rip_packet rip_packet;
+ listnode node;
+ struct connected *connected;
memset (&rip_packet, 0, sizeof (rip_packet));
@@ -2557,7 +2578,23 @@
rte = rip_packet.rte;
rte->metric = htonl (RIP_METRIC_INFINITY);
- return rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), to, ifp);
+ /* send request on each connected network */
+ LIST_LOOP(ifp->connected, connected, node)
+ {
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *) connected->address;
+
+ 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))
+ return -1;
+ }
+ return sizeof (rip_packet);
}
int
diff --git a/ripd/ripd.h b/ripd/ripd.h
index dc2f64d..29e4f67 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -385,7 +385,7 @@
void rip_redistribute_withdraw (int);
void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char);
void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t);
-void rip_interface_multicast_set (int, struct interface *);
+void rip_interface_multicast_set (int, struct connected *, int);
void rip_distribute_update_interface (struct interface *);
void rip_if_rmap_update_interface (struct interface *);