int kernel_address_delete_ipv4 (struct interface *a, struct connected *b) { zlog_debug ("%s", __func__); connected_delete_ipv4 (a, 0, &b->address->u.prefix4, b->address->prefixlen, (b->destination ? &b->destination->u.prefix4 : NULL)); return 0; }
/* Interface's address information get. */ int ifam_read (struct ifa_msghdr *ifam) { struct interface *ifp; union sockunion addr, mask, gate; /* Check does this interface exist or not. */ ifp = if_lookup_by_index (ifam->ifam_index); if (ifp == NULL) { zlog_warn ("no interface for index %d", ifam->ifam_index); return -1; } /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &gate); /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: 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); else connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &gate.sin.sin_addr, NULL); break; #ifdef HAVE_IPV6 case AF_INET6: /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &gate.sin6.sin6_addr); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &gate.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } return 0; }
int connected_route_delete (struct interface *ifp, uint32_t *addr, uint32_t *mask, int flags UNUSED_PARAM) { int masklen = u32ip_masklen (*mask); struct in_addr bcastaddr, addr_s; bcastaddr.s_addr = ipv4_broadcast_addr(*addr, masklen); addr_s.s_addr = *addr; if(connected_delete_ipv4 (ifp, ZEBRA_IFA_PEER, &addr_s, masklen, &bcastaddr)) return 1; return 0; }
/* Interface's address information get. */ int ifam_read (struct ifa_msghdr *ifam) { struct interface *ifp = NULL; union sockunion addr, mask, brd; char ifname[INTERFACE_NAMSIZ]; short ifnlen = 0; char isalias = 0; int flags = 0; ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen); if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL) { zlog_warn ("%s: no interface for ifname %s, index %d", __func__, ifname, ifam->ifam_index); return -1; } if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ)) isalias = 1; /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD field contains a broadcast address or a peer address, so we are forced to rely upon the interface type. */ if (if_is_pointopoint(ifp)) SET_FLAG(flags, ZEBRA_IFA_PEER); #if 0 /* it might seem cute to grab the interface metric here, however * we're processing an address update message, and so some systems * (e.g. FBSD) dont bother to fill in ifam_metric. Disabled, but left * in deliberately, as comment. */ ifp->metric = ifam->ifam_metric; #endif /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr, (isalias ? ifname : NULL)); else connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr); break; #ifdef HAVE_IPV6 case AF_INET6: /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, ip6_masklen (mask.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), &brd.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); #ifdef SUNOS_5 /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. * See comments for SUNOS_5 in interface.c::if_flags_mangle. * * Here we take care of case where the real IFF_UP was previously * unset (as kept in struct zebra_if.primary_state) and the mangled * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned * to unset due to the lost non-primary address having DELADDR'd. * * we must delete the interface, because in between here and next * event for this interface-name the administrator could unplumb * and replumb the interface. */ if (!if_is_up (ifp)) if_delete_update (ifp); #endif /* SUNOS_5 */ return 0; }
/* Lookup interface IPv4/IPv6 address. */ static int netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; struct interface *ifp; void *addr; void *broad; u_char flags = 0; char *label = NULL; ifa = NLMSG_DATA (h); if (ifa->ifa_family != AF_INET #ifdef HAVE_IPV6 && ifa->ifa_family != AF_INET6 #endif /* HAVE_IPV6 */ ) return 0; if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); ifp = if_lookup_by_index (ifa->ifa_index); if (ifp == NULL) { zlog_err ("netlink_interface_addr can't find interface by index %d", ifa->ifa_index); return -1; } if (IS_DEBUG_HA(kroute, KROUTE)) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; zlog_debug ("netlink_interface_addr %s %s:", lookup (nlmsg_str, h->nlmsg_type), ifp->name); if (tb[IFA_LOCAL]) zlog_debug (" IFA_LOCAL %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_ADDRESS]) zlog_debug (" IFA_ADDRESS %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_BROADCAST]) zlog_debug (" IFA_BROADCAST %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL]))) zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL])); if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]); zlog_debug (" IFA_CACHEINFO pref %d, valid %d", ci->ifa_prefered, ci->ifa_valid); } } /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); /* is there a peer address? */ if (tb[IFA_ADDRESS] && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS]))) { broad = RTA_DATA(tb[IFA_ADDRESS]); SET_FLAG (flags, KROUTE_IFA_PEER); } else /* seeking a broadcast address */ broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL); /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { zlog_debug ("%s: NULL address", __func__); return -1; } /* Flags. */ if (ifa->ifa_flags & IFA_F_SECONDARY) SET_FLAG (flags, KROUTE_IFA_SECONDARY); /* Label */ if (tb[IFA_LABEL]) label = (char *) RTA_DATA (tb[IFA_LABEL]); if (ifp && label && strcmp (ifp->name, label) == 0) label = NULL; /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, (struct in_addr *) broad, label); else connected_delete_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, (struct in_addr *) broad); } #ifdef HAVE_IPV6 if (ifa->ifa_family == AF_INET6) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad, label); else connected_delete_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad); } #endif /* HAVE_IPV6 */ return 0; }
/* Lookup interface IPv4/IPv6 address. */ int netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifaddrmsg *ifa; struct rtattr *tb [IFA_MAX + 1]; struct interface *ifp; void *addr = NULL; void *broad = NULL; u_char flags = 0; char *label = NULL; ifa = NLMSG_DATA (h); if (ifa->ifa_family != AF_INET #ifdef HAVE_IPV6 && ifa->ifa_family != AF_INET6 #endif /* HAVE_IPV6 */ ) return 0; if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); ifp = if_lookup_by_index (ifa->ifa_index); if (ifp == NULL) { zlog_err ("netlink_interface_addr can't find interface by index %d", ifa->ifa_index); return -1; } if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; if (ifp->flags & IFF_POINTOPOINT) { if (tb[IFA_LOCAL]) { addr = RTA_DATA (tb[IFA_LOCAL]); if (tb[IFA_ADDRESS]) broad = RTA_DATA (tb[IFA_ADDRESS]); else broad = NULL; } else { if (tb[IFA_ADDRESS]) addr = RTA_DATA (tb[IFA_ADDRESS]); else addr = NULL; } } else { if (tb[IFA_ADDRESS]) addr = RTA_DATA (tb[IFA_ADDRESS]); else addr = NULL; if (tb[IFA_BROADCAST]) broad = RTA_DATA(tb[IFA_BROADCAST]); else broad = NULL; } /* Flags. */ if (ifa->ifa_flags & IFA_F_SECONDARY) SET_FLAG (flags, ZEBRA_IFA_SECONDARY); /* Label */ if (tb[IFA_LABEL]) label = (char *) RTA_DATA (tb[IFA_LABEL]); if (ifp && label && strcmp (ifp->name, label) == 0) label = NULL; /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, (struct in_addr *) broad, label); else connected_delete_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, (struct in_addr *) broad, label); } #ifdef HAVE_IPV6 if (ifa->ifa_family == AF_INET6) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad); else connected_delete_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad); } #endif /* HAVE_IPV6*/ return 0; }
int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) { int len; struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; struct interface *ifp; void *addr; void *broad; uint8_t flags = 0; char *label = NULL; struct zebra_ns *zns; zns = zebra_ns_lookup(ns_id); ifa = NLMSG_DATA(h); if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) { zlog_warn( "Invalid address family: %u received from kernel interface addr change: %u", ifa->ifa_family, h->nlmsg_type); return 0; } if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); if (len < 0) { zlog_err("%s: Message received from netlink is of a broken size: %d %zu", __PRETTY_FUNCTION__, h->nlmsg_len, (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg))); return -1; } memset(tb, 0, sizeof tb); netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index); if (ifp == NULL) { flog_err( LIB_ERR_INTERFACE, "netlink_interface_addr can't find interface by index %d", ifa->ifa_index); return -1; } if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; zlog_debug("netlink_interface_addr %s %s flags 0x%x:", nl_msg_type_to_str(h->nlmsg_type), ifp->name, ifa->ifa_flags); if (tb[IFA_LOCAL]) zlog_debug(" IFA_LOCAL %s/%d", inet_ntop(ifa->ifa_family, RTA_DATA(tb[IFA_LOCAL]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_ADDRESS]) zlog_debug(" IFA_ADDRESS %s/%d", inet_ntop(ifa->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_BROADCAST]) zlog_debug(" IFA_BROADCAST %s/%d", inet_ntop(ifa->ifa_family, RTA_DATA(tb[IFA_BROADCAST]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_LABEL] && strcmp(ifp->name, RTA_DATA(tb[IFA_LABEL]))) zlog_debug(" IFA_LABEL %s", (char *)RTA_DATA(tb[IFA_LABEL])); if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]); zlog_debug(" IFA_CACHEINFO pref %d, valid %d", ci->ifa_prefered, ci->ifa_valid); } } /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); /* is there a peer address? */ if (tb[IFA_ADDRESS] && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS]))) { broad = RTA_DATA(tb[IFA_ADDRESS]); SET_FLAG(flags, ZEBRA_IFA_PEER); } else /* seeking a broadcast address */ broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL); /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { zlog_debug("%s: NULL address", __func__); return -1; } /* Flags. */ if (ifa->ifa_flags & IFA_F_SECONDARY) SET_FLAG(flags, ZEBRA_IFA_SECONDARY); /* Label */ if (tb[IFA_LABEL]) label = (char *)RTA_DATA(tb[IFA_LABEL]); if (label && strcmp(ifp->name, label) == 0) label = NULL; /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { zlog_err( "Invalid prefix length: %u received from kernel interface addr change: %u", ifa->ifa_prefixlen, h->nlmsg_type); return -1; } if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4(ifp, flags, (struct in_addr *)addr, ifa->ifa_prefixlen, (struct in_addr *)broad, label); else connected_delete_ipv4( ifp, flags, (struct in_addr *)addr, ifa->ifa_prefixlen, (struct in_addr *)broad); } if (ifa->ifa_family == AF_INET6) { if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) { zlog_err( "Invalid prefix length: %u received from kernel interface addr change: %u", ifa->ifa_prefixlen, h->nlmsg_type); return -1; } if (h->nlmsg_type == RTM_NEWADDR) { /* Only consider valid addresses; we'll not get a * notification from * the kernel till IPv6 DAD has completed, but at init * time, Quagga * does query for and will receive all addresses. */ if (!(ifa->ifa_flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) connected_add_ipv6(ifp, flags, (struct in6_addr *)addr, (struct in6_addr *)broad, ifa->ifa_prefixlen, label); } else connected_delete_ipv6(ifp, (struct in6_addr *)addr, (struct in6_addr *)broad, ifa->ifa_prefixlen); } return 0; }