diff --git a/ldpd/socket.c b/ldpd/socket.c index cf352d7204..1bb0837401 100644 --- a/ldpd/socket.c +++ b/ldpd/socket.c @@ -421,15 +421,7 @@ sock_set_ipv4_mcast(struct iface *iface) int sock_set_ipv4_mcast_loop(int fd) { - uint8_t loop = 0; - - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - (char *)&loop, sizeof(loop)) < 0) { - log_warn("%s: error setting IP_MULTICAST_LOOP", __func__); - return (-1); - } - - return (0); + return (setsockopt_ipv4_multicast_loop(fd, 0)); } int diff --git a/lib/if.c b/lib/if.c index d943d599aa..9161796160 100644 --- a/lib/if.c +++ b/lib/if.c @@ -390,7 +390,7 @@ if_lookup_exact_address (void *src, int family) } /* Lookup interface by IPv4 address. */ -struct interface * +struct connected * if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id) { struct listnode *node; @@ -399,7 +399,7 @@ if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id) struct listnode *cnode; struct interface *ifp; struct connected *c; - struct interface *match; + struct connected *match; if (family == AF_INET) { @@ -425,14 +425,14 @@ if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id) (c->address->prefixlen > bestlen)) { bestlen = c->address->prefixlen; - match = ifp; + match = c; } } } return match; } -struct interface * +struct connected * if_lookup_address (void *matchaddr, int family) { return if_lookup_address_vrf (matchaddr, family, VRF_DEFAULT); diff --git a/lib/if.h b/lib/if.h index 59141e7871..c53b9ff0e7 100644 --- a/lib/if.h +++ b/lib/if.h @@ -389,7 +389,7 @@ extern int if_cmp_name_func (char *, char *); extern struct interface *if_create (const char *name, int namelen); extern struct interface *if_lookup_by_index (ifindex_t); extern struct interface *if_lookup_exact_address (void *matchaddr, int family); -extern struct interface *if_lookup_address (void *matchaddr, int family); +extern struct connected *if_lookup_address (void *matchaddr, int family); extern struct interface *if_lookup_prefix (struct prefix *prefix); extern void if_update_vrf (struct interface *, const char *name, int namelen, @@ -399,7 +399,7 @@ extern struct interface *if_create_vrf (const char *name, int namelen, extern struct interface *if_lookup_by_index_vrf (ifindex_t, vrf_id_t vrf_id); extern struct interface *if_lookup_exact_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id); -extern struct interface *if_lookup_address_vrf (void *matchaddr, int family, +extern struct connected *if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id); extern struct interface *if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id); diff --git a/lib/sockopt.c b/lib/sockopt.c index c480cee0d7..be3ac0e4bf 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -384,7 +384,20 @@ setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, #error "Unsupported multicast API" #endif } - + +int +setsockopt_ipv4_multicast_loop (int sock, u_char val) +{ + int ret; + + ret = setsockopt (sock, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &val, + sizeof (val)); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_LOOP"); + + return ret; +} + static int setsockopt_ipv4_ifindex (int sock, ifindex_t val) { diff --git a/lib/sockopt.h b/lib/sockopt.h index d67b510b66..02f0189345 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -89,6 +89,8 @@ extern int setsockopt_ipv4_multicast(int sock, int optname, struct in_addr if_addr, unsigned int mcast_addr, ifindex_t ifindex); +extern int setsockopt_ipv4_multicast_loop (int sock, u_char val); + extern int setsockopt_ipv4_tos(int sock, int tos); /* Ask for, and get, ifindex, by whatever method is supported. */ diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 6caa38d68b..088123ea24 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -132,18 +132,16 @@ ospf_if_ipmulticast (struct ospf *top, struct prefix *p, ifindex_t ifindex) { u_char val; int ret, len; - - val = 0; - len = sizeof (val); - + /* Prevent receiving self-origined multicast packets. */ - ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); + ret = setsockopt_ipv4_multicast_loop (top->fd, 0); if (ret < 0) zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s", top->fd, safe_strerror(errno)); /* Explicitly set multicast ttl to 1 -- endo. */ val = 1; + len = sizeof (val); ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len); if (ret < 0) zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s", diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b7ef24409e..72ce5586f6 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2772,6 +2772,7 @@ ospf_read (struct thread *thread) struct ospf_header *ospfh; u_int16_t length; struct interface *ifp; + struct connected *c; /* first of all get interface pointer. */ ospf = THREAD_ARG (thread); @@ -2790,13 +2791,16 @@ ospf_read (struct thread *thread) /* Note that sockopt_iphdrincl_swab_systoh was called in ospf_recv_packet. */ if (ifp == NULL) - /* Handle cases where the platform does not support retrieving the ifindex, - and also platforms (such as Solaris 8) that claim to support ifindex - retrieval but do not. */ - ifp = if_lookup_address ((void *)&iph->ip_src, AF_INET); - - if (ifp == NULL) - return 0; + { + /* Handle cases where the platform does not support retrieving the ifindex, + and also platforms (such as Solaris 8) that claim to support ifindex + retrieval but do not. */ + c = if_lookup_address ((void *)&iph->ip_src, AF_INET); + if (c) + ifp = c->ifp; + if (ifp == NULL) + return 0; + } /* IP Header dump. */ if (IS_DEBUG_OSPF_PACKET(0, RECV)) diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index a024e3ae01..231efd0f22 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -35,6 +35,7 @@ #include "privs.h" #include "if.h" #include "vrf.h" +#include "sockopt.h" #include "pimd.h" #include "pim_mroute.h" @@ -68,7 +69,7 @@ int pim_socket_raw(int protocol) return fd; } -int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop) +int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop) { int fd; @@ -173,8 +174,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop) } } - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - (void *) &loop, sizeof(loop))) { + if (setsockopt_ipv4_multicast_loop (fd, loop)) { zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", loop ? "enable" : "disable", fd, errno, safe_strerror(errno)); diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index f0a1600818..cd29543fa0 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -39,7 +39,7 @@ #define PIM_SOCK_ERR_BIND (-11) /* Can't bind to interface */ int pim_socket_raw(int protocol); -int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, int loop); +int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop); int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, ifindex_t ifindex); int pim_socket_join_source(int fd, ifindex_t ifindex, diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index fe88eba271..fba563a6f8 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -25,6 +25,7 @@ #include "if.h" #include "log.h" #include "memory.h" +#include "sockopt.h" #include "pim_ssmpingd.h" #include "pim_time.h" @@ -150,17 +151,12 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl) return -1; } - { - int loop = 0; - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - (void *) &loop, sizeof(loop))) { - zlog_warn("%s: could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", - __PRETTY_FUNCTION__, - loop ? "enable" : "disable", - fd, errno, safe_strerror(errno)); - close(fd); - return PIM_SOCK_ERR_LOOP; - } + if (setsockopt_ipv4_multicast_loop (fd, 0)) { + zlog_warn("%s: could not disable Multicast Loopback Option on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, + fd, errno, safe_strerror(errno)); + close(fd); + return PIM_SOCK_ERR_LOOP; } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 359549ed80..6d6cb0c686 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -55,6 +55,7 @@ const struct message ri_version_msg[] = {RI_RIP_VERSION_1, "1"}, {RI_RIP_VERSION_2, "2"}, {RI_RIP_VERSION_1_AND_2, "1 2"}, + {RI_RIP_VERSION_NONE, "none"}, }; extern struct zebra_privs_t ripd_privs; @@ -536,7 +537,9 @@ rip_interface_reset (struct rip_interface *ri) ri->ri_send = RI_RIP_UNSPEC; ri->ri_receive = RI_RIP_UNSPEC; - + + ri->v2_broadcast = 0; + if (ri->auth_str) { free (ri->auth_str); @@ -1316,13 +1319,14 @@ DEFUN (no_rip_neighbor, DEFUN (ip_rip_receive_version, ip_rip_receive_version_cmd, - "ip rip receive version (1|2)", + "ip rip receive version (1|2|none)", IP_STR "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 1\n" - "RIP version 2\n") + "RIP version 2\n" + "None\n") { struct interface *ifp; struct rip_interface *ri; @@ -1330,17 +1334,21 @@ DEFUN (ip_rip_receive_version, ifp = (struct interface *)vty->index; ri = ifp->info; - /* Version 1. */ - if (atoi (argv[0]) == 1) + switch (*argv[0]) { + case '1': ri->ri_receive = RI_RIP_VERSION_1; return CMD_SUCCESS; - } - if (atoi (argv[0]) == 2) - { + case '2': ri->ri_receive = RI_RIP_VERSION_2; return CMD_SUCCESS; + case 'n': + ri->ri_receive = RI_RIP_VERSION_NONE; + return CMD_SUCCESS; + default: + break; } + return CMD_WARNING; } @@ -1518,6 +1526,41 @@ ALIAS (no_ip_rip_send_version, "Version 1\n" "Version 2\n") +DEFUN (ip_rip_v2_broadcast, + ip_rip_v2_broadcast_cmd, + "ip rip v2-broadcast", + IP_STR + "Routing Information Protocol\n" + "Send ip broadcast v2 update\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->v2_broadcast = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_v2_broadcast, + no_ip_rip_v2_broadcast_cmd, + "no ip rip v2-broadcast", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Send ip broadcast v2 update\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->v2_broadcast = 0; + return CMD_SUCCESS; +} + DEFUN (ip_rip_authentication_mode, ip_rip_authentication_mode_cmd, "ip rip authentication mode (md5|text)", @@ -1918,6 +1961,7 @@ rip_interface_config_write (struct vty *vty) (ri->ri_send == RI_RIP_UNSPEC) && (ri->ri_receive == RI_RIP_UNSPEC) && (ri->auth_type != RIP_AUTH_MD5) && + (!ri->v2_broadcast) && (ri->md5_auth_len != RIP_AUTH_MD5_SIZE) && (!ri->auth_str) && (!ri->key_chain) ) @@ -1959,6 +2003,9 @@ rip_interface_config_write (struct vty *vty) lookup (ri_version_msg, ri->ri_receive), VTY_NEWLINE); + if (ri->v2_broadcast) + vty_out (vty, " ip rip v2-broadcast%s", VTY_NEWLINE); + /* RIP authentication. */ if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE); @@ -2099,6 +2146,9 @@ rip_if_init (void) install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd); + install_element (INTERFACE_NODE, &ip_rip_v2_broadcast_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_v2_broadcast_cmd); + install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_authlen_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd); diff --git a/ripd/ripd.c b/ripd/ripd.c index 6124471161..e9d610cea7 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -812,7 +812,15 @@ rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, struct interface *ifp) { struct rip_interface *ri; - char *auth_str; + char *auth_str = (char *) &rte->prefix; + int i; + + /* reject passwords with zeros in the middle of the string */ + for (i = strlen (auth_str); i < 16; i++) + { + if (auth_str[i] != '\0') + return 0; + } if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 simple password authentication from %s", @@ -827,8 +835,6 @@ rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, /* Simple password authentication. */ if (ri->auth_str) { - auth_str = (char *) &rte->prefix; - if (strncmp (auth_str, ri->auth_str, 16) == 0) return 1; } @@ -841,7 +847,7 @@ rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, if (keychain == NULL) return 0; - key = key_match_for_accept (keychain, (char *) &rte->prefix); + key = key_match_for_accept (keychain, auth_str); if (key) return 1; } @@ -1333,30 +1339,23 @@ rip_response_process (struct rip_packet *packet, int size, /* Make socket for RIP protocol. */ static int -rip_create_socket (struct sockaddr_in *from) +rip_create_socket (void) { int ret; int sock; struct sockaddr_in addr; memset (&addr, 0, sizeof (struct sockaddr_in)); - - if (!from) - { - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - addr.sin_len = sizeof (struct sockaddr_in); + addr.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - } else { - memcpy(&addr, from, sizeof(addr)); - } - /* sending port must always be the RIP port */ addr.sin_port = htons (RIP_PORT_DEFAULT); /* Make datagram socket. */ - sock = socket (AF_INET, SOCK_DGRAM, 0); + sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { zlog_err("Cannot create UDP socket: %s", safe_strerror(errno)); @@ -1366,6 +1365,7 @@ rip_create_socket (struct sockaddr_in *from) sockopt_broadcast (sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock); + setsockopt_ipv4_multicast_loop (sock, 0); #ifdef RIP_RECVMSG setsockopt_pktinfo (sock); #endif /* RIP_RECVMSG */ @@ -1406,7 +1406,7 @@ static int rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, struct connected *ifc) { - int ret, send_sock; + int ret; struct sockaddr_in sin; assert (ifc != NULL); @@ -1462,38 +1462,16 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, { sin.sin_port = to->sin_port; sin.sin_addr = to->sin_addr; - send_sock = rip->sock; } else { - struct sockaddr_in from; - sin.sin_port = htons (RIP_PORT_DEFAULT); sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); - - /* multicast send should bind to local interface address */ - memset (&from, 0, sizeof (from)); - from.sin_family = AF_INET; - from.sin_port = htons (RIP_PORT_DEFAULT); - from.sin_addr = ifc->address->u.prefix4; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - from.sin_len = sizeof (struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - - /* - * 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. - */ - if ( (send_sock = rip_create_socket (&from)) < 0) - { - zlog_warn("rip_send_packet could not create socket."); - return -1; - } - rip_interface_multicast_set (send_sock, ifc); + + rip_interface_multicast_set (rip->sock, ifc); } - ret = sendto (send_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) @@ -1503,9 +1481,6 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, if (ret < 0) zlog_warn ("can't send packet : %s", safe_strerror (errno)); - if (!to) - close(send_sock); - return ret; } @@ -1681,6 +1656,9 @@ rip_request_process (struct rip_packet *packet, int size, } else { + if (ntohs (rte->family) != AF_INET) + return; + /* Examine the list of RTEs in the Request one by one. For each entry, look up the destination in the router's routing database and, if there is a route, put that route's metric in @@ -1803,7 +1781,7 @@ rip_read (struct thread *t) int len; int vrecv; socklen_t fromlen; - struct interface *ifp; + struct interface *ifp = NULL; struct connected *ifc; struct rip_interface *ri; struct prefix p; @@ -1836,8 +1814,10 @@ rip_read (struct thread *t) } /* Which interface is this packet comes from. */ - ifp = if_lookup_address ((void *)&from.sin_addr, AF_INET); - + ifc = if_lookup_address ((void *)&from.sin_addr, AF_INET); + if (ifc) + ifp = ifc->ifp; + /* RIP packet received */ if (IS_RIP_DEBUG_EVENT) zlog_debug ("RECV packet from %s port %d on %s", @@ -1928,15 +1908,9 @@ rip_read (struct thread *t) /* RIP Version check. RFC2453, 4.6 and 5.1 */ vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv : ri->ri_receive); - if ((packet->version == RIPv1) && !(vrecv & RIPv1)) - { - if (IS_RIP_DEBUG_PACKET) - zlog_debug (" packet's v%d doesn't fit to if version spec", - packet->version); - rip_peer_bad_packet (&from); - return -1; - } - if ((packet->version == RIPv2) && !(vrecv & RIPv2)) + if (vrecv == RI_RIP_VERSION_NONE || + ((packet->version == RIPv1) && !(vrecv & RIPv1)) || + ((packet->version == RIPv2) && !(vrecv & RIPv2))) { if (IS_RIP_DEBUG_PACKET) zlog_debug (" packet's v%d doesn't fit to if version spec", @@ -2434,20 +2408,22 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to, static void rip_update_interface (struct connected *ifc, u_char version, int route_type) { + struct interface *ifp = ifc->ifp; + struct rip_interface *ri = ifp->info; struct sockaddr_in to; /* When RIP version is 2 and multicast enable interface. */ - if (version == RIPv2 && if_is_multicast (ifc->ifp)) + if (version == RIPv2 && !ri->v2_broadcast && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) - zlog_debug ("multicast announce on %s ", ifc->ifp->name); + zlog_debug ("multicast announce on %s ", ifp->name); rip_output_process (ifc, NULL, route_type, version); return; } /* If we can't send multicast packet, send it with unicast. */ - if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp)) + if (if_is_broadcast (ifp) || if_is_pointopoint (ifp)) { if (ifc->address->family == AF_INET) { @@ -2469,7 +2445,7 @@ rip_update_interface (struct connected *ifc, u_char version, int route_type) if (IS_RIP_DEBUG_EVENT) zlog_debug("%s announce to %s on %s", CONNECTED_PEER(ifc) ? "unicast" : "broadcast", - inet_ntoa (to.sin_addr), ifc->ifp->name); + inet_ntoa (to.sin_addr), ifp->name); rip_output_process (ifc, &to, route_type, version); } @@ -2539,21 +2515,14 @@ rip_update_process (int route_type) { p = &rp->p; - ifp = if_lookup_prefix (p); - if (! ifp) + connected = if_lookup_address (&p->u.prefix4, AF_INET); + if (! connected) { zlog_warn ("Neighbor %s doesnt have connected interface!", inet_ntoa (p->u.prefix4)); continue; } - if ( (connected = connected_lookup_prefix (ifp, p)) == NULL) - { - zlog_warn ("Neighbor %s doesnt have connected network", - inet_ntoa (p->u.prefix4)); - continue; - } - /* Set destination address and port */ memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_addr = p->u.prefix4; @@ -2579,11 +2548,7 @@ rip_update (struct thread *t) /* Triggered updates may be suppressed if a regular update is due by the time the triggered update would be sent. */ - if (rip->t_triggered_interval) - { - thread_cancel (rip->t_triggered_interval); - rip->t_triggered_interval = NULL; - } + RIP_TIMER_OFF (rip->t_triggered_interval); rip->trigger = 0; /* Register myself. */ @@ -2637,11 +2602,7 @@ rip_triggered_update (struct thread *t) rip->t_triggered_update = NULL; /* Cancel interval timer. */ - if (rip->t_triggered_interval) - { - thread_cancel (rip->t_triggered_interval); - rip->t_triggered_interval = NULL; - } + RIP_TIMER_OFF (rip->t_triggered_interval); rip->trigger = 0; /* Logging triggered update. */ @@ -2729,7 +2690,7 @@ rip_create (void) rip->obuf = stream_new (1500); /* Make socket. */ - rip->sock = rip_create_socket (NULL); + rip->sock = rip_create_socket (); if (rip->sock < 0) return rip->sock; @@ -2819,11 +2780,7 @@ rip_event (enum rip_event event, int sock) rip->t_read = thread_add_read (master, rip_read, NULL, sock); break; case RIP_UPDATE_EVENT: - if (rip->t_update) - { - thread_cancel (rip->t_update); - rip->t_update = NULL; - } + RIP_TIMER_OFF (rip->t_update); jitter = rip_update_jitter (rip->update_time); rip->t_update = thread_add_timer (master, rip_update, NULL, @@ -3918,11 +3875,7 @@ rip_clean (void) RIP_TIMER_OFF (rip->t_triggered_interval); /* Cancel read thread. */ - if (rip->t_read) - { - thread_cancel (rip->t_read); - rip->t_read = NULL; - } + THREAD_READ_OFF (rip->t_read); /* Close RIP socket. */ if (rip->sock >= 0) diff --git a/ripd/ripd.h b/ripd/ripd.h index 3de23ec334..cb4764a7f1 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -258,6 +258,9 @@ struct rip_interface int ri_send; int ri_receive; + /* RIPv2 broadcast mode */ + int v2_broadcast; + /* RIPv2 authentication type. */ int auth_type; @@ -347,6 +350,7 @@ struct rip_md5_data #define RI_RIP_VERSION_1 1 #define RI_RIP_VERSION_2 2 #define RI_RIP_VERSION_1_AND_2 3 +#define RI_RIP_VERSION_NONE 4 /* N.B. stuff will break if (RIPv1 != RI_RIP_VERSION_1) || (RIPv2 != RI_RIP_VERSION_2) */ @@ -369,14 +373,7 @@ enum rip_event } while (0) /* Macro for timer turn off. */ -#define RIP_TIMER_OFF(X) \ - do { \ - if (X) \ - { \ - thread_cancel (X); \ - (X) = NULL; \ - } \ - } while (0) +#define RIP_TIMER_OFF(X) THREAD_TIMER_OFF(X) /* Prototypes. */ extern void rip_init (void); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index c4dec7e7b1..a8742ec9a4 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -65,7 +65,7 @@ ripng_multicast_join (struct interface *ifp) struct ipv6_mreq mreq; int save_errno; - if (if_is_up (ifp) && if_is_multicast (ifp)) { + if (if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; @@ -116,7 +116,7 @@ ripng_multicast_leave (struct interface *ifp) int ret; struct ipv6_mreq mreq; - if (if_is_up (ifp) && if_is_multicast (ifp)) { + if (if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 2a32b934f2..82c4877485 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -829,8 +829,10 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, * with the new one in below. */ break; - /* Metrics are same. Keep "rinfo" null and the new route - * is added in the ECMP list in below. */ + /* Metrics are same. Unless ECMP is disabled, keep "rinfo" null and + * the new route is added in the ECMP list in below. */ + if (! ripng->ecmp) + break; } } @@ -874,11 +876,24 @@ ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) && (rinfo->ifindex == ifp->ifindex)); + /* + * RFC 2080 - Section 2.4.2: + * "If the new metric is the same as the old one, examine the timeout + * for the existing route. If it is at least halfway to the expiration + * point, switch to the new route. This heuristic is optional, but + * highly recommended". + */ + if (!ripng->ecmp && !same && + rinfo->metric == rte->metric && rinfo->t_timeout && + (thread_timer_remain_second (rinfo->t_timeout) < (ripng->timeout_time / 2))) + { + ripng_ecmp_replace (&newinfo); + } /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old one; do the following actions: */ - if ((same && rinfo->metric != rte->metric) || + else if ((same && rinfo->metric != rte->metric) || rte->metric < rinfo->metric) { if (listcount (list) == 1) @@ -2155,6 +2170,54 @@ DEFUN (show_ipv6_ripng_status, return CMD_SUCCESS; } +DEFUN (clear_ipv6_rip, + clear_ipv6_rip_cmd, + "clear ipv6 ripng", + CLEAR_STR + IPV6_STR + "Clear IPv6 RIP database") +{ + struct route_node *rp; + struct ripng_info *rinfo; + struct list *list; + struct listnode *listnode; + + /* Clear received RIPng routes */ + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + { + list = rp->info; + if (list == NULL) + continue; + + for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) + { + if (! ripng_route_rte (rinfo)) + continue; + + if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) + ripng_zebra_ipv6_delete (rp); + break; + } + + if (rinfo) + { + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + listnode_delete (list, rinfo); + ripng_info_free (rinfo); + } + + if (list_isempty (list)) + { + list_free (list); + rp->info = NULL; + route_unlock_node (rp); + } + } + + return CMD_SUCCESS; +} + DEFUN (router_ripng, router_ripng_cmd, "router ripng", @@ -3032,6 +3095,8 @@ ripng_init () install_element (VIEW_NODE, &show_ipv6_ripng_cmd); install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd); + install_element (ENABLE_NODE, &clear_ipv6_rip_cmd); + install_element (CONFIG_NODE, &router_ripng_cmd); install_element (CONFIG_NODE, &no_router_ripng_cmd); diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 25c7aff26b..c9c32ce311 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -282,7 +282,7 @@ send_packet(struct interface *ifp, char buf[256]; struct in_pktinfo *pktinfo; u_long src; - int on; + u_char on; if (!(ifp->flags & IFF_UP)) return; @@ -323,12 +323,8 @@ send_packet(struct interface *ifp, zlog_warn("sendto %s", safe_strerror (errno)); } - if(dst != INADDR_BROADCAST) { - on = 0; - if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, - (char *)&on,sizeof(on)) < 0) - zlog_warn("sendto %s", safe_strerror (errno)); - } + if(dst != INADDR_BROADCAST) + setsockopt_ipv4_multicast_loop (irdp_sock, 0); memset(&sockdst,0,sizeof(sockdst)); sockdst.sin_family=AF_INET;