From 3fb9cd6ef456959b6eff939d5c316f6785c2dda4 Mon Sep 17 00:00:00 2001 From: hasso Date: Tue, 19 Oct 2004 19:44:43 +0000 Subject: OK. Here it is - PtP patch from Andrew J. Schorr. No problems with ospfd, ripd might need some more testing though. --- ChangeLog | 7 +++ bgpd/ChangeLog | 6 +++ bgpd/bgp_nexthop.c | 8 +-- lib/ChangeLog | 15 ++++++ lib/if.c | 84 +++++++++++-------------------- lib/if.h | 13 ++++- lib/prefix.c | 26 +++++++++- lib/prefix.h | 8 +++ lib/zclient.c | 15 +++++- ospfd/ChangeLog | 13 +++++ ospfd/ospf_interface.c | 40 +++++++++++---- ospfd/ospf_lsa.c | 2 +- ospfd/ospf_snmp.c | 2 +- ospfd/ospf_vty.c | 5 ++ ospfd/ospfd.c | 34 ++++--------- ripd/ChangeLog | 12 +++++ ripd/rip_interface.c | 132 +++++++++++++++++++++++++------------------------ ripd/ripd.c | 16 +++--- zebra/ChangeLog | 12 +++++ zebra/connected.c | 46 ++++++++++++++++- zebra/interface.c | 6 +-- zebra/rt_netlink.c | 4 +- 22 files changed, 328 insertions(+), 178 deletions(-) diff --git a/ChangeLog b/ChangeLog index e46bb112..e732bca5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2004-10-19 Andrew J. Schorr + + * lib, zebra, ripd, ospfd, bgpd: Support NULL connected destination + pointers properly everywhere. Fix point-to-point logic to + support links where a dedicated subnet has been assigned. + PtP links with /31 subnets should now work where supported by O/S. + 2004-10-11 Paul Jakma * bump version to 0.97.1, release imminent. diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog index 37ab163b..e82843be 100644 --- a/bgpd/ChangeLog +++ b/bgpd/ChangeLog @@ -1,3 +1,9 @@ +2004-10-19 Andrew J. Schorr + + * bgp_nexthop.c: (bgp_connected_add) Connected destination pointer + may be NULL. + (bgp_connected_delete) ditto. + 2004-10-14 Hasso Tepper * bgp_dump.c: Make dump configuration appear in vtysh. diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 4100e3df..c50eeedd 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -666,7 +666,7 @@ bgp_connected_add (struct connected *ifc) p.family = AF_INET; p.prefixlen = addr->prefixlen; - if (if_is_pointopoint (ifp)) + if (CONNECTED_POINTOPOINT_HOST(ifc)) p.u.prefix4 = dest->u.prefix4; else p.u.prefix4 = addr->u.prefix4; @@ -697,7 +697,7 @@ bgp_connected_add (struct connected *ifc) p.family = AF_INET6; p.prefixlen = addr->prefixlen; - if (if_is_pointopoint (ifp)) + if (if_is_pointopoint (ifp) && dest) p.u.prefix6 = dest->u.prefix6; else p.u.prefix6 = addr->u.prefix6; @@ -751,7 +751,7 @@ bgp_connected_delete (struct connected *ifc) p.family = AF_INET; p.prefixlen = addr->prefixlen; - if (if_is_pointopoint (ifp)) + if (CONNECTED_POINTOPOINT_HOST(ifc)) p.u.prefix4 = dest->u.prefix4; else p.u.prefix4 = addr->u.prefix4; @@ -782,7 +782,7 @@ bgp_connected_delete (struct connected *ifc) p.family = AF_INET6; p.prefixlen = addr->prefixlen; - if (if_is_pointopoint (ifp)) + if (if_is_pointopoint (ifp) && dest) p.u.prefix6 = dest->u.prefix6; else p.u.prefix6 = addr->u.prefix6; diff --git a/lib/ChangeLog b/lib/ChangeLog index 31fb15be..d0a33d40 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,18 @@ +2004-10-19 Andrew J. Schorr + + * zclient.c: (zebra_interface_address_read) If the destination address + is encoded as all zeroes, load it as a NULL pointer. + * if.h: Add comment describing struct connected destination field + and indicating that it may be NULL. Define macros + CONNECTED_DEST_HOST and CONNECTED_POINTOPOINT_HOST to help + with PtP logic (distinguish between host and subnet addressing). + * if.c: (if_lookup_address) Fix PtP logic to handle subnet addressing + properly, + (connected_lookup_address) ditto. + (connected_add_by_prefix) Handle case where destination is NULL, + * prefix.[c|h]: New functions ipv4_network_addr and + ipv4_broadcast_addr. + 2004-10-13 Hasso Tepper * command.c: Make CMD_ERR_NOTHING_TODO nonfatal if reading diff --git a/lib/if.c b/lib/if.c index 259b8423..5519b2ae 100644 --- a/lib/if.c +++ b/lib/if.c @@ -258,17 +258,13 @@ if_lookup_address (struct in_addr src) { struct listnode *node; struct prefix addr; - struct prefix best; + int bestlen = 0; struct listnode *cnode; struct interface *ifp; struct prefix *p; struct connected *c; struct interface *match; - /* Zero structures - get rid of rubbish from stack */ - memset(&addr, 0, sizeof(addr)); - memset(&best, 0, sizeof(best)); - addr.family = AF_INET; addr.u.prefix4 = src; addr.prefixlen = IPV4_MAX_BITLEN; @@ -283,31 +279,22 @@ if_lookup_address (struct in_addr src) { c = getdata (cnode); - if (if_is_pointopoint (ifp)) + if (c->address && (c->address->family == AF_INET)) { - p = c->address; - - if (p && p->family == AF_INET) + if (CONNECTED_POINTOPOINT_HOST(c)) { -#ifdef OLD_RIB /* PTP links are conventionally identified - by the address of the far end - MAG */ - if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) - return ifp; -#endif - p = c->destination; - if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src)) + /* PTP links are conventionally identified + by the address of the far end - MAG */ + if (IPV4_ADDR_SAME (&c->destination->u.prefix4, &src)) return ifp; } - } - else - { - p = c->address; - - if (p->family == AF_INET) + else { - if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen) + p = c->address; + + if (prefix_match (p, &addr) && p->prefixlen > bestlen) { - best = *p; + bestlen = p->prefixlen; match = ifp; } } @@ -680,16 +667,11 @@ struct connected * connected_lookup_address (struct interface *ifp, struct in_addr dst) { struct prefix addr; - struct prefix best; struct listnode *cnode; struct prefix *p; struct connected *c; struct connected *match; - /* Zero structures - get rid of rubbish from stack */ - memset(&addr, 0, sizeof(addr)); - memset(&best, 0, sizeof(best)); - addr.family = AF_INET; addr.u.prefix4 = dst; addr.prefixlen = IPV4_MAX_BITLEN; @@ -700,35 +682,24 @@ connected_lookup_address (struct interface *ifp, struct in_addr dst) { c = getdata (cnode); - if (if_is_pointopoint (ifp)) - { - p = c->address; - - if (p && p->family == AF_INET) + if (c->address && (c->address->family == AF_INET)) + { + if (CONNECTED_POINTOPOINT_HOST(c)) { -#ifdef OLD_RIB /* PTP links are conventionally identified - by the address of the far end - MAG */ - if (IPV4_ADDR_SAME (&p->u.prefix4, &dst)) - return c; -#endif - p = c->destination; - if (p && IPV4_ADDR_SAME (&p->u.prefix4, &dst)) + /* PTP links are conventionally identified + by the address of the far end - MAG */ + if (IPV4_ADDR_SAME (&c->destination->u.prefix4, &dst)) return c; } - } - else - { - p = c->address; - - if (p->family == AF_INET) + else { - if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen) - { - best = *p; - match = c; - } + p = c->address; + + if (prefix_match (p, &addr) && + (!match || (p->prefixlen > match->address->prefixlen))) + match = c; } - } + } } return match; } @@ -748,8 +719,11 @@ connected_add_by_prefix (struct interface *ifp, struct prefix *p, memcpy (ifc->address, p, sizeof(struct prefix)); /* Fetch dest address */ - ifc->destination = prefix_new(); - memcpy (ifc->destination, destination, sizeof(struct prefix)); + if (destination) + { + ifc->destination = prefix_new(); + memcpy (ifc->destination, destination, sizeof(struct prefix)); + } /* Add connected address to the interface. */ listnode_add (ifp->connected, ifc); diff --git a/lib/if.h b/lib/if.h index 218f1026..7afb2ae9 100644 --- a/lib/if.h +++ b/lib/if.h @@ -148,12 +148,23 @@ struct connected /* Address of connected network. */ struct prefix *address; - struct prefix *destination; + struct prefix *destination; /* broadcast or peer address; may be NULL */ /* Label for Linux 2.2.X and upper. */ char *label; }; +/* Given an IPV4 struct connected, this macro determines whether a /32 + peer address has been supplied (i.e. there is no subnet assigned) */ +#define CONNECTED_DEST_HOST(C) \ + ((C)->destination && ((C)->address->prefixlen == IPV4_MAX_PREFIXLEN)) + +/* Given an IPV4 struct connected, this macro determins whether it is + a point-to-point link with a /32 peer address (i.e. there + is no dedicated subnet for the PtP link) */ +#define CONNECTED_POINTOPOINT_HOST(C) \ + (((C)->ifp->flags & IFF_POINTOPOINT) && CONNECTED_DEST_HOST(C)) + /* Interface hook sort. */ #define IF_NEW_HOOK 0 #define IF_DELETE_HOOK 1 diff --git a/lib/prefix.c b/lib/prefix.c index d9751e3f..3f3c4e8e 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -247,7 +247,7 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p) /* Get prefix length. */ plen = (u_char) atoi (++pnt); - if (plen > 32) + if (plen > IPV4_MAX_PREFIXLEN) return 0; p->family = AF_INET; @@ -648,7 +648,7 @@ void apply_classful_mask_ipv4 (struct prefix_ipv4 *p) destination = ntohl (p->prefix.s_addr); - if (p->prefixlen == 32); + if (p->prefixlen == IPV4_MAX_PREFIXLEN); /* do nothing for host routes */ else if (IN_CLASSC (destination)) { @@ -667,6 +667,28 @@ void apply_classful_mask_ipv4 (struct prefix_ipv4 *p) } } +in_addr_t +ipv4_network_addr (in_addr_t hostaddr, int masklen) +{ + struct in_addr mask; + + masklen2ip (masklen, &mask); + return hostaddr & mask.s_addr; +} + +in_addr_t +ipv4_broadcast_addr (in_addr_t hostaddr, int masklen) +{ + struct in_addr mask; + + masklen2ip (masklen, &mask); + return (masklen != IPV4_MAX_PREFIXLEN-1) ? + /* normal case */ + (hostaddr | ~mask.s_addr) : + /* special case for /31 */ + (hostaddr ^ ~mask.s_addr); +} + /* Utility function to convert ipv4 netmask to prefixes ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16" ex.) "1.0.0.0" NULL => "1.0.0.0/8" */ diff --git a/lib/prefix.h b/lib/prefix.h index e4f17ab0..0546095b 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -153,6 +153,14 @@ void apply_classful_mask_ipv4 (struct prefix_ipv4 *); u_char ip_masklen (struct in_addr); void masklen2ip (int, struct in_addr *); +/* returns the network portion of the host address */ +in_addr_t ipv4_network_addr (in_addr_t hostaddr, int masklen); +/* given the address of a host on a network and the network mask length, + * calculate the broadcast address for that network; + * special treatment for /31: returns the address of the other host + * on the network by flipping the host bit */ +in_addr_t ipv4_broadcast_addr (in_addr_t hostaddr, int masklen); + int netmask_str2prefix_str (const char *, const char *, char *); #ifdef HAVE_IPV6 diff --git a/lib/zclient.c b/lib/zclient.c index 98829f61..dfb2f2fc 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -644,6 +644,17 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->bandwidth = stream_getl (s); } +static int +memconstant(const void *s, int c, size_t n) +{ + const u_char *p = s; + + while (n-- > 0) + if (*p++ != c) + return 0; + return 1; +} + struct connected * zebra_interface_address_read (int type, struct stream *s) { @@ -688,7 +699,9 @@ zebra_interface_address_read (int type, struct stream *s) if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { - ifc = connected_add_by_prefix(ifp, &p, &d); + /* N.B. NULL destination pointers are encoded as all zeroes */ + ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ? + NULL : &d)); if (ifc != NULL) ifc->flags = ifc_flags; } diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog index 914ed930..31ee303d 100644 --- a/ospfd/ChangeLog +++ b/ospfd/ChangeLog @@ -1,3 +1,16 @@ +2004-10-19 Andrew J. Schorr + + * ospf_snmp.c: (ospf_snmp_if_update) Fix logic to handle PtP links + with dedicated subnets properly. + * ospf_lsa.c: (lsa_link_ptop_set) ditto. + * ospfd.c: (ospf_network_match_iface) ditto. + (ospf_network_run) ditto. + * ospf_interface.c: (ospf_if_is_configured) ditto. + (ospf_if_lookup_by_prefix) ditto. + (ospf_if_lookup_recv_if) ditto. + * ospf_vty.c: (show_ip_ospf_interface_sub) Display the peer or + broadcast address if present. + 2004-10-13 Hasso Tepper * ospf_main.c: Unbreak compilation with ospfapi disabled. diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 277d508b..e74c375a 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -338,27 +338,45 @@ ospf_if_free (struct ospf_interface *oi) /* * check if interface with given address is configured and -* return it if yes. +* return it if yes. special treatment for PtP networks. */ struct ospf_interface * ospf_if_is_configured (struct ospf *ospf, struct in_addr *address) { struct listnode *node; struct ospf_interface *oi; - struct prefix *addr; + struct prefix_ipv4 addr; + + addr.family = AF_INET; + addr.prefix = *address; + addr.prefixlen = IPV4_MAX_PREFIXLEN; for (node = listhead (ospf->oiflist); node; nextnode (node)) if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) { if (oi->type == OSPF_IFTYPE_POINTOPOINT) - addr = oi->connected->destination; + { + if (CONNECTED_DEST_HOST(oi->connected)) + { + /* match only destination addr, since local addr is most likely + * not unique (borrowed from another interface) */ + if (IPV4_ADDR_SAME (address, + &oi->connected->destination->u.prefix4)) + return oi; + } + else + { + /* special leniency: match if addr is anywhere on PtP subnet */ + if (prefix_match(oi->address,(struct prefix *)&addr)) + return oi; + } + } else - addr = oi->address; - - if (IPV4_ADDR_SAME (address, &addr->u.prefix4)) - return oi; + { + if (IPV4_ADDR_SAME (address, &oi->address->u.prefix4)) + return oi; + } } - return NULL; } @@ -417,7 +435,8 @@ ospf_if_lookup_by_prefix (struct ospf *ospf, struct prefix_ipv4 *p) { if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) { - if (oi->type == OSPF_IFTYPE_POINTOPOINT) + if ((oi->type == OSPF_IFTYPE_POINTOPOINT) && + CONNECTED_DEST_HOST(oi->connected)) { prefix_copy (&ptmp, oi->connected->destination); ptmp.prefixlen = IPV4_MAX_BITLEN; @@ -454,7 +473,8 @@ ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src) if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; - if (oi->type == OSPF_IFTYPE_POINTOPOINT) + if ((oi->type == OSPF_IFTYPE_POINTOPOINT) && + CONNECTED_DEST_HOST(oi->connected)) { if (IPV4_ADDR_SAME (&oi->connected->destination->u.prefix4, &src)) return oi; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 3ad6ddf0..f1478a3d 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -517,7 +517,7 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) links++; } - if (oi->connected->destination != NULL) + if (CONNECTED_DEST_HOST(oi->connected)) { /* Option 1: link_type = LSA_LINK_TYPE_STUB; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index db0aaf6e..0cf257da 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1435,7 +1435,7 @@ ospf_snmp_if_update (struct interface *ifp) /* Lookup first IPv4 address entry. */ LIST_LOOP (ifp->connected, ifc, nn) { - if (if_is_pointopoint (ifp)) + if (CONNECTED_POINTOPOINT_HOST(ifc)) p = ifc->destination; else p = ifc->address; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 0ecb6fb4..c84da747 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2550,6 +2550,11 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, vty_out (vty, " Internet Address %s/%d,", inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen); + if (oi->connected->destination) + vty_out (vty, " %s %s,", + ((ifp->flags & IFF_POINTOPOINT) ? "Peer" : "Broadcast"), + inet_ntoa (oi->connected->destination->u.prefix4)); + vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area), VTY_NEWLINE); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 0a988e0f..054c3316 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -686,31 +686,17 @@ ospf_network_match_iface(struct connected *co, struct prefix *net) * PtP special case: network specified == iface peer addr -> ospf */ - /* For PtP, match if peer address matches network address exactly. - * This can be addr/32 or addr/p for p < 32, but the addr must match - * exactly; this is not a test for falling within the prefix. This + /* For PtP, match if peer address matches network address exactly + * in situations where the peer address is available and the prefix + * length is 32 (i.e. a dedicated subnet has not been assigned). + * This is not a test for falling within the prefix. This * test is solely for compatibility with zebra. - */ - if (if_is_pointopoint (co->ifp) && - IPV4_ADDR_SAME ( &(co->destination->u.prefix4), &(net->u.prefix4))) - return 1; - -#if 0 - /* Decline to accept PtP if dst address does not match the - * prefix. (ifdefed out because this is a workaround, not the - * desired behavior.) */ - if (if_is_pointopoint (co->ifp) && - ! prefix_match (net, co->destination)) - return 0; -#endif - - /* If the address is within the prefix, accept. Note that this - * applies to PtP as well as other types. + * + * If not PtP, accept if the address is within the prefix. */ - if (prefix_match (net, co->address)) - return 1; - - return 0; /* no match */ + return CONNECTED_POINTOPOINT_HOST(co) ? + IPV4_ADDR_SAME ( &(co->destination->u.prefix4), &(net->u.prefix4)) : + prefix_match (net, co->address); } void @@ -748,7 +734,7 @@ ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area) if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) continue; - if (if_is_pointopoint (co->ifp)) + if (CONNECTED_POINTOPOINT_HOST(co)) addr = co->destination; else addr = co->address; diff --git a/ripd/ChangeLog b/ripd/ChangeLog index ee878ff6..ae67e72d 100644 --- a/ripd/ChangeLog +++ b/ripd/ChangeLog @@ -1,3 +1,15 @@ +2004-10-19 Andrew J. Schorr + + * ripd.c: (rip_update_interface) if connected->destination is NULL, + get the broadcast address with ipv4_broadcast_addr() + * rip_interface.c: (rip_interface_multicast_set) + connected->destination may be NULL. Improve message if + setsockopt_multicast_ipv4 fails. Improve message if bind fails. + (rip_request_interface_send) If connected->destination is NULL, + get the broadcast address with ipv4_broadcast_addr(). + (if_valid_neighbor) Handle PtP subnet addressing properly. + Speed up code by using prefix_match properly. + 2004-10-13 Hasso Tepper * ripd_snmp.c: Remove defaults used to initialize smux connection to diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 509d5ed5..19f6f114 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -143,16 +143,16 @@ rip_interface_multicast_set (int sock, struct connected *connected) int ret; struct servent *sp; struct sockaddr_in from; - struct in_addr addr; + struct in_addr addr; struct prefix_ipv4 *p; if (connected != NULL) { - if (if_is_pointopoint(connected->ifp)) - p = (struct prefix_ipv4 *) connected->destination; - else - p = (struct prefix_ipv4 *) connected->address; - addr = p->prefix; + if (if_is_pointopoint(connected->ifp) && CONNECTED_DEST_HOST(connected)) + p = (struct prefix_ipv4 *) connected->destination; + else + p = (struct prefix_ipv4 *) connected->address; + addr = p->prefix; } else { @@ -161,46 +161,52 @@ rip_interface_multicast_set (int sock, struct connected *connected) if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, addr, 0, connected->ifp->ifindex) < 0) - { - zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d, ifindex %d", - sock, connected->ifp->ifindex); - return; - } + { + zlog_warn ("Can't setsockopt IP_MULTICAST_IF on fd %d to " + "source address %s for interface %s", + sock, inet_ntoa(addr), + (connected ? connected->ifp->name : "(unknown)")); + return; + } - /* Bind myself. */ - memset (&from, 0, sizeof (struct sockaddr_in)); + /* Bind myself. */ + memset (&from, 0, sizeof (struct sockaddr_in)); - /* Set RIP port. */ - sp = getservbyname ("router", "udp"); - if (sp) - from.sin_port = sp->s_port; - else - from.sin_port = htons (RIP_PORT_DEFAULT); + /* Set RIP port. */ + sp = getservbyname ("router", "udp"); + if (sp) + from.sin_port = sp->s_port; + else + from.sin_port = htons (RIP_PORT_DEFAULT); /* Address should be any address. */ - from.sin_family = AF_INET; + from.sin_family = AF_INET; if (connected) - addr = ((struct prefix_ipv4 *) connected->address)->prefix; - from.sin_addr = addr; + addr = ((struct prefix_ipv4 *) connected->address)->prefix; + from.sin_addr = addr; #ifdef HAVE_SIN_LEN - from.sin_len = sizeof (struct sockaddr_in); + from.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_SIN_LEN */ - if (ripd_privs.change (ZPRIVS_RAISE)) - zlog_err ("rip_interface_multicast_set: could not raise privs"); + 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)); - if (ret < 0) - { - zlog_warn ("Can't bind socket: %s", strerror (errno)); - } - - if (ripd_privs.change (ZPRIVS_LOWER)) - zlog_err ("rip_interface_multicast_set: could not lower privs"); + if (ret < 0) + { + zlog_warn ("Can't bind socket fd %d to %s port %d for " + "interface %s: %s", + sock,inet_ntoa(from.sin_addr), + (int)ntohs(from.sin_port), + (connected ? connected->ifp->name : "(unknown)"), + strerror (errno)); + } - return; + if (ripd_privs.change (ZPRIVS_LOWER)) + zlog_err ("rip_interface_multicast_set: could not lower privs"); - } + return; +} /* Send RIP request packet to specified interface. */ void @@ -229,17 +235,22 @@ rip_request_interface_send (struct interface *ifp, u_char version) for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { - struct prefix_ipv4 *p; struct connected *connected; connected = getdata (cnode); - p = (struct prefix_ipv4 *) connected->destination; - if (p->family == AF_INET) + if (connected->address->family == AF_INET) { memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); - to.sin_addr = p->prefix; + if (connected->destination) + /* use specified broadcast or point-to-point destination addr */ + to.sin_addr = connected->destination->u.prefix4; + else + /* calculate the appropriate broadcast address */ + to.sin_addr.s_addr = + ipv4_broadcast_addr(connected->address->u.prefix4.s_addr, + connected->address->prefixlen); if (IS_RIP_DEBUG_EVENT) zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr)); @@ -439,6 +450,11 @@ if_valid_neighbor (struct in_addr addr) struct listnode *node; struct connected *connected = NULL; struct prefix_ipv4 *p; + struct prefix_ipv4 pa; + + pa.family = AF_INET; + pa.prefix = addr; + pa.prefixlen = IPV4_MAX_PREFIXLEN; for (node = listhead (iflist); node; nextnode (node)) { @@ -449,9 +465,6 @@ if_valid_neighbor (struct in_addr addr) for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { - struct prefix *pxn = NULL; /* Prefix of the neighbor */ - struct prefix *pxc = NULL; /* Prefix of the connected network */ - connected = getdata (cnode); if (if_is_pointopoint (ifp)) @@ -464,34 +477,23 @@ if_valid_neighbor (struct in_addr addr) return 1; p = (struct prefix_ipv4 *) connected->destination; - if (p && IPV4_ADDR_SAME (&p->prefix, &addr)) - return 1; + if (p) + { + if (IPV4_ADDR_SAME (&p->prefix, &addr)) + return 1; + } + else + { + if (prefix_match(connected->address,(struct prefix *)&pa)) + return 1; + } } } else { - p = (struct prefix_ipv4 *) connected->address; - - if (p->family != AF_INET) - continue; - - pxn = prefix_new(); - pxn->family = AF_INET; - pxn->prefixlen = 32; - pxn->u.prefix4 = addr; - - pxc = prefix_new(); - prefix_copy(pxc, (struct prefix *) p); - apply_mask(pxc); - - if (prefix_match (pxc, pxn)) - { - prefix_free (pxn); - prefix_free (pxc); - return 1; - } - prefix_free(pxc); - prefix_free(pxn); + if ((connected->address->family == AF_INET) && + prefix_match(connected->address,(struct prefix *)&pa)) + return 1; } } } diff --git a/ripd/ripd.c b/ripd/ripd.c index 2b4e1b2f..94324f03 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -2391,7 +2391,6 @@ void rip_update_interface (struct interface *ifp, u_char version, int route_type, struct connected *sconn) { - struct prefix_ipv4 *p; struct connected *connected; struct listnode *node; struct sockaddr_in to; @@ -2415,15 +2414,18 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type, { connected = getdata (node); - /* Fetch broadcast address or poin-to-point destination - address . */ - p = (struct prefix_ipv4 *) connected->destination; - - if (p->family == AF_INET) + if (connected->address->family == AF_INET) { /* Destination address and port setting. */ memset (&to, 0, sizeof (struct sockaddr_in)); - to.sin_addr = p->prefix; + if (connected->destination) + /* use specified broadcast or point-to-point destination addr */ + to.sin_addr = connected->destination->u.prefix4; + else + /* calculate the appropriate broadcast address */ + to.sin_addr.s_addr = + ipv4_broadcast_addr(connected->address->u.prefix4.s_addr, + connected->address->prefixlen); to.sin_port = htons (RIP_PORT_DEFAULT); if (IS_RIP_DEBUG_EVENT) diff --git a/zebra/ChangeLog b/zebra/ChangeLog index 506e3ae3..e3774706 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -1,3 +1,15 @@ +2004-10-19 Andrew J. Schorr + + * rt_netlink.c: (netlink_interface_addr) For PtP interfaces, ignore + tb[IFA_ADDRESS] if it's the same as tb[IFA_LOCAL]. + * interface.c: (ip_address_install) Use new ipv4_broadcast_addr + function. + * connected.c: (connected_up_ipv4) Use CONNECTED_POINTOPOINT_HOST + macro. + (connected_down_ipv4) ditto. + (connected_add_ipv4) Validate destination address, print warnings + if it does not make sense. + 2004-10-19 Hasso Tepper * zserv.c: Fix regression introduced with zserv cleanup. diff --git a/zebra/connected.c b/zebra/connected.c index a043ef48..9a6fd669 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -70,7 +70,7 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) p.prefixlen = addr->prefixlen; /* Point-to-point check. */ - if (if_is_pointopoint (ifp) && dest) + if (CONNECTED_POINTOPOINT_HOST(ifc)) p.prefix = dest->prefix; else p.prefix = addr->prefix; @@ -116,7 +116,49 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, p->family = AF_INET; p->prefix = *broad; ifc->destination = (struct prefix *) p; + + /* validate the destination address */ + if (ifp->flags & IFF_POINTOPOINT) + { + if (IPV4_ADDR_SAME(addr,broad)) + zlog_warn("warning: PtP interface %s has same local and peer " + "address %s, routing protocols may malfunction", + ifp->name,inet_ntoa(*addr)); + else if ((prefixlen != IPV4_MAX_PREFIXLEN) && + (ipv4_network_addr(addr->s_addr,prefixlen) != + ipv4_network_addr(broad->s_addr,prefixlen))) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_warn("warning: PtP interface %s network mismatch: local " + "%s/%d vs. peer %s, routing protocols may malfunction", + ifp->name, + inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])), + prefixlen, + inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1]))); + } + } + else + { + if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen)) + { + char buf[2][INET_ADDRSTRLEN]; + struct in_addr bcalc; + bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen); + zlog_warn("warning: interface %s broadcast addr %s/%d != " + "calculated %s, routing protocols may malfunction", + ifp->name, + inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])), + prefixlen, + inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1]))); + } + } + } + else + /* no broadcast or destination address was supplied */ + if (prefixlen == IPV4_MAX_PREFIXLEN) + zlog_warn("warning: interface %s with addr %s/%d needs a peer address", + ifp->name,inet_ntoa(*addr),prefixlen); /* Label of this address. */ if (label) @@ -166,7 +208,7 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) p.prefixlen = addr->prefixlen; /* Point-to-point check. */ - if (dest && if_is_pointopoint (ifp)) + if (CONNECTED_POINTOPOINT_HOST(ifc)) p.prefix = dest->prefix; else p.prefix = addr->prefix; diff --git a/zebra/interface.c b/zebra/interface.c index 5664f41a..a1d0332a 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1107,7 +1107,6 @@ ip_address_install (struct vty *vty, struct interface *ifp, struct prefix_ipv4 cp; struct connected *ifc; struct prefix_ipv4 *p; - struct in_addr mask; int ret; ret = str2prefix_ipv4 (addr_str, &cp); @@ -1129,12 +1128,11 @@ ip_address_install (struct vty *vty, struct interface *ifp, ifc->address = (struct prefix *) p; /* Broadcast. */ - if (p->prefixlen <= 30) + if (p->prefixlen <= IPV4_MAX_PREFIXLEN-2) { p = prefix_ipv4_new (); *p = cp; - masklen2ip (p->prefixlen, &mask); - p->prefix.s_addr |= ~mask.s_addr; + p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr,p->prefixlen); ifc->destination = (struct prefix *) p; } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ee61cb27..50e83b77 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -596,7 +596,9 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) if (tb[IFA_LOCAL]) { addr = RTA_DATA (tb[IFA_LOCAL]); - if (tb[IFA_ADDRESS]) + if (tb[IFA_ADDRESS] && + memcmp(RTA_DATA(tb[IFA_ADDRESS]),RTA_DATA(tb[IFA_LOCAL]),4)) + /* if IFA_ADDRESS != IFA_LOCAL, then it's the peer address */ broad = RTA_DATA (tb[IFA_ADDRESS]); else broad = NULL; -- cgit v1.2.1