diff options
-rw-r--r-- | zebra/ChangeLog | 37 | ||||
-rw-r--r-- | zebra/connected.c | 12 | ||||
-rw-r--r-- | zebra/connected.h | 5 | ||||
-rw-r--r-- | zebra/if_ioctl.c | 3 | ||||
-rw-r--r-- | zebra/if_ioctl_solaris.c | 50 | ||||
-rw-r--r-- | zebra/if_proc.c | 2 | ||||
-rw-r--r-- | zebra/interface.c | 15 | ||||
-rw-r--r-- | zebra/ioctl_solaris.c | 50 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 14 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 4 |
10 files changed, 149 insertions, 43 deletions
diff --git a/zebra/ChangeLog b/zebra/ChangeLog index 0d69e751..e1723603 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -1,3 +1,40 @@ +2005-11-03 Paul Jakma <paul.jakma@sun.com> + + * connected.{c,h}: Include memory.h + (connected_add_ipv4) Use MTYPE for ifc label. + (connected_add_ipv6) Also should accept label. Store it in ifp. + (connected_del_ipv4) Taking label as argument is pointless. + * rt_netlink.c: (netlink_interface_addr) update label usage + for connected_{add,delete} functions. + * if_ioctl.c: (if_getaddrs) NULL label for connected_add_ipv6. + * if_ioctl_solaris.c: (interface_list_ioctl) Pass LIFC_NOXMIT + so we also find out about NOXMIT interfaces like VNI. + Bit of hackery to turn interface names into the primary + interface name, later with routing socket messages we only + will about primary interfaces anyway, so we must normalise + the name. + (if_get_addr) take label as argument, so it can + be passed to connected_add. + If label is provided, then it is interface name to issue the + ioctl for address information on, not the ifp name. + (interface_list) List AF_UNSPEC too, just in case. + * if_proc.c: (ifaddr_proc_ipv6) label for connected_add_ipv6. + * interface.c: (if_addr_wakeup) Some very bogus code - sets + IFF_RUNNING - add comment. + (if_refresh) + (ip_address_install) Use MTYPE for ifc label. + * ioctl_solaris.c: (if_mangle_up) New function. Hackery to make + IFF_UP reflect whether any addresses are left on the + interface, as we get signalled for IFF_UP flags change on the + primary interface only. Logical interfaces dont generate + IFINFO, but we do get an RTM_DELADDR. + (if_get_flags) Call if_mangle_up before return. + * kernel_socket.c: (ifam_read) Fixup calls to + connected_{add,delete} to match above changes. Rename gate + variable to brd, less confusing. + Pass the interface name as a label, if it is not same name + as ifp->name. + 2005-10-11 Paul Jakma <paul.jakma@sun.com> * connected.{c,h}: (connected_{add,delete}_ipv4) label should diff --git a/zebra/connected.c b/zebra/connected.c index 58d964fc..105e4b11 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -29,6 +29,7 @@ #include "rib.h" #include "table.h" #include "log.h" +#include "memory.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" @@ -219,7 +220,7 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, /* Label of this address. */ if (label) - ifc->label = strdup (label); + ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); /* Check same connected route. */ if ((current = connected_check (ifp, (struct prefix *) ifc->address))) @@ -267,8 +268,7 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) /* Delete connected IPv4 route to the interface. */ void connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, - u_char prefixlen, struct in_addr *broad, - const char *label) + u_char prefixlen, struct in_addr *broad) { struct prefix_ipv4 p; struct connected *ifc; @@ -330,7 +330,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) /* Add connected IPv6 route to the interface. */ void connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr, - u_char prefixlen, struct in6_addr *broad) + u_char prefixlen, struct in6_addr *broad, char *label) { struct prefix_ipv6 *p; struct connected *ifc; @@ -356,6 +356,10 @@ connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr, ifc->destination = (struct prefix *) p; } + /* Label of this address. */ + if (label) + ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); + if ((current = connected_check (ifp, (struct prefix *) ifc->address))) connected_withdraw (current); /* implicit update of existing address */ diff --git a/zebra/connected.h b/zebra/connected.h index 26e809c4..289b03c7 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -33,8 +33,7 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, extern void connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, - u_char prefixlen, struct in_addr *broad, - const char *label); + u_char prefixlen, struct in_addr *broad); extern void connected_up_ipv4 (struct interface *, struct connected *); extern void connected_down_ipv4 (struct interface *, struct connected *); @@ -42,7 +41,7 @@ extern void connected_down_ipv4 (struct interface *, struct connected *); #ifdef HAVE_IPV6 extern void connected_add_ipv6 (struct interface *ifp, struct in6_addr *address, - u_char prefixlen, struct in6_addr *broad); + u_char prefixlen, struct in6_addr *broad, char *label); extern void connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, u_char prefixlen, struct in6_addr *broad); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 66d8327d..b00a29cd 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -305,7 +305,8 @@ if_getaddrs (void) } #endif - connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt); + connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, + dest_pnt, NULL); } #endif /* HAVE_IPV6 */ } diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index efa65060..898c1610 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -34,7 +34,7 @@ #include "zebra/interface.h" void lifreq_set_name (struct lifreq *, struct interface *); -static int if_get_addr (struct interface *, struct sockaddr *); +static int if_get_addr (struct interface *, struct sockaddr *, const char *); static void interface_info_ioctl (struct interface *); extern struct zebra_privs_t zserv_privs; @@ -71,7 +71,7 @@ interface_list_ioctl (int af) calculate_lifc_len: /* must hold privileges to enter here */ lifn.lifn_family = af; - lifn.lifn_flags = 0; + lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */ ret = ioctl (sock, SIOCGLIFNUM, &lifn); save_errno = errno; @@ -108,7 +108,7 @@ calculate_lifc_len: /* must hold privileges to enter here */ lastneeded = needed; lifconf.lifc_family = af; - lifconf.lifc_flags = 0; + lifconf.lifc_flags = LIFC_NOXMIT; lifconf.lifc_len = needed; lifconf.lifc_buf = buf; @@ -138,9 +138,22 @@ calculate_lifc_len: /* must hold privileges to enter here */ for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq)) { - ifp = if_get_by_name_len(lifreq->lifr_name, - strnlen(lifreq->lifr_name, - sizeof(lifreq->lifr_name))); + /* we treat Solaris logical interfaces as addresses, because that is + * how PF_ROUTE on Solaris treats them. Hence we can not directly use + * the lifreq_name to get the ifp. We need to normalise the name + * before attempting get. + * + * Solaris logical interface names are in the form of: + * <interface name>:<logical interface id> + */ + unsigned int normallen = 0; + + while ( (normallen < sizeof(lifreq->lifr_name)) + && ( *(lifreq->lifr_name + normallen) != '\0') + && ( *(lifreq->lifr_name + normallen) != ':') ) + normallen++; + + ifp = if_get_by_name_len(lifreq->lifr_name, normallen); if (lifreq->lifr_addr.ss_family == AF_INET) ifp->flags |= IFF_IPV4; @@ -158,7 +171,15 @@ calculate_lifc_len: /* must hold privileges to enter here */ if_add_update (ifp); interface_info_ioctl (ifp); - if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr); + + /* If a logical interface pass the full name so it can be + * as a label on the address + */ + if ( *(lifreq->lifr_name + normallen) != '\0') + if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, + lifreq->lifr_name); + else + if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL); lifreq++; } @@ -209,8 +230,9 @@ if_get_index (struct interface *ifp) #define SIN(s) ((struct sockaddr_in *)(s)) #define SIN6(s) ((struct sockaddr_in6 *)(s)) +/* Retrieve address information for the given ifp */ static int -if_get_addr (struct interface *ifp, struct sockaddr *addr) +if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) { int ret; struct lifreq lifreq; @@ -219,8 +241,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr) u_char prefixlen = 0; afi_t af; - /* Interface's name and address family. */ - strncpy (lifreq.lifr_name, ifp->name, IFNAMSIZ); + /* Interface's name and address family. + * We need to use the logical interface name / label, if we've been + * given one, in order to get the right address + */ + strncpy (lifreq.lifr_name, (label : label ? ifp->name), IFNAMSIZ); /* Interface's address. */ memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr)); @@ -306,11 +331,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr) /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4 (ifp, 0, &SIN (addr)->sin_addr, prefixlen, - (struct in_addr *) dest_pnt, NULL); + (struct in_addr *) dest_pnt, label); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, &SIN6 (addr)->sin6_addr, prefixlen, - (struct in6_addr *) dest_pnt); + (struct in6_addr *) dest_pnt, label); #endif /* HAVE_IPV6 */ return 0; @@ -332,6 +357,7 @@ interface_list () { interface_list_ioctl (AF_INET); interface_list_ioctl (AF_INET6); + interface_list_ioctl (AF_UNSPEC); } struct connected * diff --git a/zebra/if_proc.c b/zebra/if_proc.c index 3257d03c..6002595a 100644 --- a/zebra/if_proc.c +++ b/zebra/if_proc.c @@ -240,7 +240,7 @@ ifaddr_proc_ipv6 () str2in6_addr (addr, &p.prefix); p.prefixlen = plen; - connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL); + connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL, ifname); } fclose (fp); return 0; diff --git a/zebra/interface.c b/zebra/interface.c index 49fffcf5..5f9c7a23 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -209,6 +209,16 @@ if_addr_wakeup (struct interface *ifp) { if (! if_is_up (ifp)) { + /* XXX: WTF is it trying to set flags here? + * caller has just gotten a new interface, has been + * handed the flags already. This code has no business + * trying to override administrative status of the interface. + * The only call path to here which doesn't originate from + * kernel event is irdp - what on earth is it trying to do? + * + * further RUNNING is not a settable flag on any system + * I (paulj) am aware of. + */ if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } @@ -236,6 +246,7 @@ if_addr_wakeup (struct interface *ifp) { if (! if_is_up (ifp)) { + /* XXX: See long comment above */ if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } @@ -1172,7 +1183,7 @@ ip_address_install (struct vty *vty, struct interface *ifp, /* Label. */ if (label) - ifc->label = strdup (label); + ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); /* Add to linked list. */ listnode_add (ifp->connected, ifc); @@ -1363,7 +1374,7 @@ ipv6_address_install (struct vty *vty, struct interface *ifp, /* Label. */ if (label) - ifc->label = strdup (label); + ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); /* Add to linked list. */ listnode_add (ifp->connected, ifc); diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index 43e1e83f..ec1d2c44 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -274,11 +274,35 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc) return 0; } +/* Solaris IFF_UP flag reflects only the primary interface as the + * routing socket only sends IFINFO for the primary interface. Hence + * ~IFF_UP does not per se imply all the logical interfaces are also + * down - which we only know of as addresses. Instead we must determine + * whether the interface really is up or not according to how many + * addresses are still attached. (Solaris always sends RTM_DELADDR if + * an interface, logical or not, goes ~IFF_UP). + * + * Ie, we mangle IFF_UP to reflect whether or not there are addresses + * left in struct connected, not the actual underlying IFF_UP flag + * (which corresponds to just one address of all the logical interfaces) + * + * Setting IFF_UP within zebra to administratively shutdown the + * interface will affect only the primary interface/address on Solaris. + */ +static inline void +if_mangle_up (struct interface *ifp) +{ + if (listcount(ifp->connected) > 0) + SET_FLAG (ifp->flags, IFF_UP); + else + UNSET_FLAG (ifp->flags, IFF_UP); +} + /* get interface flags */ void if_get_flags (struct interface *ifp) { - int ret; + int ret4, ret6; struct lifreq lifreq; unsigned long flags4 = 0, flags6 = 0; @@ -286,25 +310,27 @@ if_get_flags (struct interface *ifp) { lifreq_set_name (&lifreq, ifp); - ret = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq); - - flags4 = (lifreq.lifr_flags & 0xffffffff); - if (!(flags4 & IFF_UP)) - flags4 &= ~IFF_IPV4; + ret4 = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq); + + if (!ret4) + flags4 = (lifreq.lifr_flags & 0xffffffff); } if (ifp->flags & IFF_IPV6) { lifreq_set_name (&lifreq, ifp); - ret = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq); - - flags6 = (lifreq.lifr_flags & 0xffffffff); - if (!(flags6 & IFF_UP)) - flags6 &= ~IFF_IPV6; + ret6 = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq); + + if (!ret6) + flags6 = (lifreq.lifr_flags & 0xffffffff); } + + /* only update flags if one of above succeeded */ + if ( !(ret4 && ret6) ) + ifp->flags = (flags4 | flags6); - ifp->flags = (flags4 | flags6); + if_mangle_up (ifp); } /* Set interface flags */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index f391d53a..c264437d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -465,7 +465,7 @@ int ifam_read (struct ifa_msghdr *ifam) { struct interface *ifp; - union sockunion addr, mask, gate; + union sockunion addr, mask, brd; /* Check does this interface exist or not. */ ifp = if_lookup_by_index (ifam->ifam_index); @@ -476,7 +476,7 @@ ifam_read (struct ifa_msghdr *ifam) } /* Allocate and read address information. */ - ifam_read_mesg (ifam, &addr, &mask, &gate); + ifam_read_mesg (ifam, &addr, &mask, &brd); /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); @@ -488,11 +488,12 @@ ifam_read (struct ifa_msghdr *ifam) if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), - &gate.sin.sin_addr, NULL); + &brd.sin.sin_addr, + (isalias ? ifname : NULL) ); else connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), - &gate.sin.sin_addr, NULL); + &brd.sin.sin_addr); break; #ifdef HAVE_IPV6 case AF_INET6: @@ -505,12 +506,13 @@ ifam_read (struct ifa_msghdr *ifam) connected_add_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), - &gate.sin6.sin6_addr); + &brd.sin6.sin6_addr, + (isalias ? ifname : NULL) ); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), - &gate.sin6.sin6_addr); + &brd.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 254c3bd7..6db8496d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -686,7 +686,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) else connected_delete_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, - (struct in_addr *) broad, label); + (struct in_addr *) broad); } #ifdef HAVE_IPV6 if (ifa->ifa_family == AF_INET6) @@ -694,7 +694,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, - (struct in6_addr *) broad); + (struct in6_addr *) broad, label); else connected_delete_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, |