/* Set up interface's address, netmask (and broadcas? ). Linux or Solaris uses ifname:number semantics to set IP address aliases. */ int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in broad; struct sockaddr_in mask; struct prefix_ipv4 ifaddr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); ifaddr = *p; strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx), sizeof(ifreq.ifr_name)); addr.sin_addr = p->prefix; addr.sin_family = p->family; memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); if (ret < 0) return ret; /* We need mask for make broadcast addr. */ masklen2ip(p->prefixlen, &mask.sin_addr); if (dplane_ctx_intf_is_broadcast(ctx)) { apply_mask_ipv4(&ifaddr); addr.sin_addr = ifaddr.prefix; broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); broad.sin_family = p->family; memcpy(&ifreq.ifr_broadaddr, &broad, sizeof(struct sockaddr_in)); ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq); if (ret < 0) return ret; } mask.sin_family = p->family; #ifdef SUNOS_5 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask)); #else memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in)); #endif /* SUNOS5 */ ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq); if (ret < 0) return ret; return 0; }
/* Set up interface's address, netmask (and broadcast? ). Solaris uses ifname:number semantics to set IP address aliases. */ int if_set_prefix(struct interface *ifp, struct connected *ifc) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in broad; struct sockaddr_in mask; struct prefix_ipv4 ifaddr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)ifc->address; ifaddr = *p; strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); addr.sin_addr = p->prefix; addr.sin_family = p->family; memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); if (ret < 0) return ret; /* We need mask for make broadcast addr. */ masklen2ip(p->prefixlen, &mask.sin_addr); if (if_is_broadcast(ifp)) { apply_mask_ipv4(&ifaddr); addr.sin_addr = ifaddr.prefix; broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); broad.sin_family = p->family; memcpy(&ifreq.ifr_broadaddr, &broad, sizeof(struct sockaddr_in)); ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq); if (ret < 0) return ret; } mask.sin_family = p->family; #ifdef SUNOS_5 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask)); #else memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in)); #endif /* SUNOS_5 */ ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq); return ((ret < 0) ? ret : 0); }
static int if_get_hwaddr (struct interface *ifp) { int ret; struct ifreq ifreq; int i; strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq); if (ret < 0) ifp->hw_addr_len = 0; else { memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); for (i = 0; i < 6; i++) if (ifp->hw_addr[i] != 0) break; if (i == 6) ifp->hw_addr_len = 0; else ifp->hw_addr_len = 6; } return 0; }
/* Set up interface's IP address, netmask (and broadcas? ). *BSD may has ifaliasreq structure. */ int if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; struct sockaddr_in addr; struct sockaddr_in mask; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)ifc->address; memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_addr = p->prefix; addr.sin_family = p->family; #ifdef HAVE_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; #ifdef HAVE_SIN_LEN mask.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq); if (ret < 0) return ret; return 0; }
/* get interface MTU */ void if_get_mtu (struct interface *ifp) { struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); #if defined(SIOCGIFMTU) if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) { zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)"); ifp->mtu = -1; return; } #ifdef SUNOS_5 ifp->mtu = ifreq.ifr_metric; #else ifp->mtu = ifreq.ifr_mtu; #endif /* SUNOS_5 */ #else zlog (NULL, LOG_INFO, "Can't lookup mtu on this system"); ifp->mtu = -1; #endif }
/* get interface flags */ void if_get_flags (struct interface *ifp) { int ret; struct ifreq ifreq; #ifdef HAVE_BSD_LINK_DETECT struct ifmediareq ifmr; #endif /* HAVE_BSD_LINK_DETECT */ ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); return; } #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */ /* Per-default, IFF_RUNNING is held high, unless link-detect says * otherwise - we abuse IFF_RUNNING inside kroute as a link-state flag, * following practice on Linux and Solaris kernels */ SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); if (CHECK_FLAG (ifp->status, KROUTE_INTERFACE_LINKDETECTION)) { (void) memset(&ifmr, 0, sizeof(ifmr)); strncpy (ifmr.ifm_name, ifp->name, IFNAMSIZ); /* Seems not all interfaces implement this ioctl */ if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno)); else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */ { if (ifmr.ifm_status & IFM_ACTIVE) SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); else UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); } } #endif /* HAVE_BSD_LINK_DETECT */ if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff)); }
/* get interface flags */ void if_get_flags (struct interface *ifp) { int ret = 0; struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); return; } if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff)); }
/* Get interface's index by ioctl. */ int if_get_index (struct interface_FOO *ifp) { #if defined(HAVE_IF_NAMETOINDEX) /* Modern systems should have if_nametoindex(3). */ ifp->ifindex = if_nametoindex(ifp->name); #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES) /* Fall-back for older linuxes. */ int ret; struct ifreq ifreq; static int if_fake_index; ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); if (ret < 0) { /* Linux 2.0.X does not have interface index. */ ifp->ifindex = if_fake_index++; return ifp->ifindex; } /* OK we got interface index. */ #ifdef ifr_ifindex ifp->ifindex = ifreq.ifr_ifindex; #else ifp->ifindex = ifreq.ifr_index; #endif #else /* Linux 2.2.X does not provide individual interface index for aliases and we know it. For others issue a warning. */ #if !defined(HAVE_BROKEN_ALIASES) #ifndef _MSC_VER #warning "Using if_fake_index. You may want to add appropriate" #endif #ifndef _MSC_VER #warning "mapping from ifname to ifindex for your system..." #endif #endif /* This branch probably won't provide usable results, but anyway... */ static int if_fake_index = 1; ifp->ifindex = if_fake_index++; #endif return ifp->ifindex; }
/* * Helper for interface-addr install, non-netlink */ static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx) { int ret; struct ifaliasreq addreq; struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); memset(&addreq, 0, sizeof(addreq)); strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; addr.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof(struct sockaddr_in); #endif memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); if (dplane_ctx_intf_is_connected(ctx)) { p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx); memset(&mask, 0, sizeof(struct sockaddr_in)); peer.sin_addr = p->prefix; peer.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN peer.sin_len = sizeof(struct sockaddr_in); #endif memcpy(&addreq.ifra_broadaddr, &peer, sizeof(struct sockaddr_in)); } memset(&mask, 0, sizeof(struct sockaddr_in)); masklen2ip(p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin_len = sizeof(struct sockaddr_in); #endif memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in)); ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq); if (ret < 0) return ret; return 0; }
/* * get interface metric * -- if value is not avaliable set -1 */ void if_get_metric (struct interface *ifp) { #ifdef SIOCGIFMETRIC struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) return; ifp->metric = ifreq.ifr_metric; if (ifp->metric == 0) ifp->metric = 1; #else /* SIOCGIFMETRIC */ ifp->metric = -1; #endif /* SIOCGIFMETRIC */ }
/* * get interface metric * -- if value is not avaliable set -1 */ void if_get_metric (struct interface *ifp) { struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) { return; } ifp->metric = ifreq.ifr_metric; if (ifp->metric == 0) { ifp->metric = 1; } return; }
/* get interface flags */ void if_get_flags (struct interface *ifp) { int ret; struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { perror ("ioctl"); return; } ifp->flags = ifreq.ifr_flags & 0x0000ffff; }
/* get interface MTU */ void if_get_mtu (struct interface *ifp) { struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) { zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)"); ifp->mtu6 = ifp->mtu = -1; return; } ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu; /* propogate */ zebra_interface_up_update(ifp); }
/* Unset interface's flag. */ int if_unset_flags (struct interface *ifp, unsigned long flags) { int ret; struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags &= ~flags; ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_info ("can't unset interface flags"); return ret; } return 0; }
/* Unset interface's flag. */ int if_unset_flags (struct interface *ifp, uint64_t flags) { int ret = 0; struct ifreq ifreq; memset (&ifreq, 0, sizeof(struct ifreq)); ifreq_set_name (&ifreq, ifp); ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags &= ~flags; ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_info ("can't unset interface flags"); return ret; } return 0; }
/* Set up interface's address, netmask (and broadcas? ). Linux or Solaris uses ifname:number semantics to set IP address aliases. */ int if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; ifreq_set_name (&ifreq, ifp); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_family = p->family; memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); if (ret < 0) return ret; return 0; }
/* Set up interface's address, netmask (and broadcas? ). Linux or Solaris uses ifname:number semantics to set IP address aliases. */ int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx), sizeof(ifreq.ifr_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = p->family; memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); if (ret < 0) return ret; return 0; }
/* Get interface's index by ioctl. */ int if_get_index (struct interface *ifp) { static int if_fake_index = 1; #ifdef HAVE_BROKEN_ALIASES /* Linux 2.2.X does not provide individual interface index for aliases. */ ifp->ifindex = if_fake_index++; return ifp->ifindex; #else #ifdef SIOCGIFINDEX int ret; struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); if (ret < 0) { /* Linux 2.0.X does not have interface index. */ ifp->ifindex = if_fake_index++; return ifp->ifindex; } /* OK we got interface index. */ #ifdef ifr_ifindex ifp->ifindex = ifreq.ifr_ifindex; #else ifp->ifindex = ifreq.ifr_index; #endif return ifp->ifindex; #else ifp->ifindex = if_fake_index++; return ifp->ifindex; #endif /* SIOCGIFINDEX */ #endif /* HAVE_BROKEN_ALIASES */ }
/* Interface address lookup by ioctl. This function only looks up IPv4 address. */ int if_get_addr (struct interface *ifp) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in mask; struct sockaddr_in dest; struct in_addr *dest_pnt; u_char prefixlen; /* Interface's name and address family. */ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); ifreq.ifr_addr.sa_family = AF_INET; /* Interface's address. */ ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); /* Interface's network mask. */ ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno)); return ret; } return 0; } #ifdef ifr_netmask memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); #else memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); #endif /* ifr_netmask */ prefixlen = ip_masklen (mask.sin_addr); /* Point to point or borad cast address pointer init. */ dest_pnt = NULL; if (ifp->flags & IFF_POINTOPOINT) { ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; } if (ifp->flags & IFF_BROADCAST) { ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; } /* Set address to the interface. */ connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL); return 0; }
int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) { return if_ioctl(request, buffer); }
/* Retrieve address information for the given ifp */ static int if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) { int ret; struct lifreq lifreq; struct sockaddr_storage mask, dest; char *dest_pnt = NULL; u_char prefixlen = 0; afi_t af; int flags = 0; /* 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)); af = addr->sa_family; /* Point to point or broad cast address pointer init. */ dest_pnt = NULL; if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0) { memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr)); if (af == AF_INET) dest_pnt = (char *) &(SIN (&dest)->sin_addr); else dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr); flags = ZEBRA_IFA_PEER; } if (af == AF_INET) { ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name, safe_strerror (errno)); return ret; } return 0; } memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); prefixlen = ip_masklen (SIN (&mask)->sin_addr); if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0)) { memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = (char *) &SIN (&dest)->sin_addr; } } #ifdef HAVE_IPV6 else if (af == AF_INET6) { if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0) { if (ifp->flags & IFF_POINTOPOINT) prefixlen = IPV6_MAX_BITLEN; else zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", ifp->name, safe_strerror (errno)); } else { prefixlen = lifreq.lifr_addrlen; } } #endif /* HAVE_IPV6 */ /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen, (struct in_addr *) dest_pnt, label); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, (struct in6_addr *) dest_pnt, label); #endif /* HAVE_IPV6 */ return 0; }