int mpls_socket_udp_recvfrom(mpls_socket_mgr_handle handle, mpls_socket_handle socket, uint8_t * buffer, int size, mpls_dest * from) { int ret; unsigned int ifindex = 0; struct iovec iov; struct cmsghdr *cmsg; struct in_pktinfo *pktinfo; struct sockaddr addr; char buff [sizeof (*cmsg) + sizeof (*pktinfo)]; struct msghdr msgh = {&addr, sizeof(struct sockaddr), &iov, 1, buff, sizeof (*cmsg) + sizeof (*pktinfo), 0}; iov.iov_base = buffer; iov.iov_len = size; ret = recvmsg(socket->fd,&msgh,0); if (ret < 0 && errno != EAGAIN) { return 0; } cmsg = CMSG_FIRSTHDR(&msgh); if (cmsg != NULL && cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); ifindex = pktinfo->ipi_ifindex; from->if_handle = if_lookup_by_index(ifindex); _sockaddr2mpls_dest((const struct sockaddr*)&addr, from); } return ret; }
/* Interface adding function */ int ifan_read (struct if_announcemsghdr *ifan) { struct interface *ifp; ifp = if_lookup_by_index (ifan->ifan_index); if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL) { /* Create Interface */ ifp = if_get_by_name (ifan->ifan_name); ifp->ifindex = ifan->ifan_index; if_add_update (ifp); } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) { if_delete_update (ifp); if_delete (ifp); } if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); return 0; }
const char * ifindex2ifname (unsigned int idx) { struct interface *ifp; return ((ifp = if_lookup_by_index(idx)) != NULL) ? ifp->ifDescr : "unknown"; }
const char * ifindex2ifname (unsigned int index) { struct interface_FOO *ifp; return ((ifp = if_lookup_by_index(index)) != NULL) ? ifp->name : "unknown"; }
/* 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; }
struct connected * zebra_interface_address_read (int type, struct stream *s) { unsigned int ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; int family; int plen; u_char ifc_flags; memset (&p, 0, sizeof(p)); memset (&d, 0, sizeof(d)); /* Get interface index. */ ifindex = stream_getl (s); /* Lookup index. */ ifp = if_lookup_by_index (ifindex); if (ifp == NULL) { zlog_warn ("zebra_interface_address_read(%s): " "Can't find interface by ifindex: %d ", (type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"), ifindex); return NULL; } /* Fetch flag. */ ifc_flags = stream_getc (s); /* Fetch interface address. */ family = p.family = stream_getc (s); plen = prefix_blen (&p); stream_get (&p.u.prefix, s, plen); p.prefixlen = stream_getc (s); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); d.family = family; if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* 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; } else { assert (type == ZEBRA_INTERFACE_ADDRESS_DELETE); ifc = connected_delete_by_prefix(ifp, &p); } return ifc; }
char * if_indextoname (unsigned int ifindex, char *name) { struct interface *ifp; if (!(ifp = if_lookup_by_index(ifindex))) return NULL; strncpy (name, ifp->ifDescr, IFNAMSIZ); return ifp->ifDescr; }
static void nhrp_interface_update_nbma(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL; struct interface *nbmaifp = NULL; union sockunion nbma; sockunion_family(&nbma) = AF_UNSPEC; if (nifp->source) nbmaifp = if_lookup_by_name(nifp->source); switch (ifp->ll_type) { case ZEBRA_LLT_IPGRE: { struct in_addr saddr = {0}; netlink_gre_get_info(ifp->ifindex, &nifp->grekey, &nifp->linkidx, &saddr); debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name, nifp->grekey, nifp->linkidx, saddr.s_addr); if (saddr.s_addr) sockunion_set(&nbma, AF_INET, (u_char *) &saddr.s_addr, sizeof(saddr.s_addr)); else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL) nbmaifp = if_lookup_by_index(nifp->linkidx); } break; default: break; } if (nbmaifp) nbmanifp = nbmaifp->info; if (nbmaifp != nifp->nbmaifp) { if (nifp->nbmaifp) notifier_del(&nifp->nbmanifp_notifier); nifp->nbmaifp = nbmaifp; if (nbmaifp) { notifier_add(&nifp->nbmanifp_notifier, &nbmanifp->notifier_list, nhrp_interface_interface_notifier); debugf(NHRP_DEBUG_IF, "%s: bound to %s", ifp->name, nbmaifp->name); } } if (nbmaifp) { if (sockunion_family(&nbma) == AF_UNSPEC) nbma = nbmanifp->afi[AFI_IP].addr; nhrp_interface_update_mtu(ifp, AFI_IP); nhrp_interface_update_source(ifp); } if (!sockunion_same(&nbma, &nifp->nbma)) { nifp->nbma = nbma; nhrp_interface_update(nifp->ifp); debugf(NHRP_DEBUG_IF, "%s: NBMA address changed", ifp->name); notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED); } nhrp_interface_update(ifp); }
int ifstat_update_sysctl () { caddr_t ref, buf, end; size_t bufsiz; struct if_msghdr *ifm; struct interface *ifp; #define MIBSIZ 6 int mib[MIBSIZ] = { CTL_NET, PF_ROUTE, 0, 0, /* AF_INET & AF_INET6 */ NET_RT_IFLIST, 0 }; /* Query buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { zlog_warn ("sysctl() error by %s", strerror (errno)); return -1; } /* We free this memory at the end of this function. */ ref = buf = XMALLOC (MTYPE_TMP, bufsiz); /* Fetch interface informations into allocated buffer. */ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) { zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno)); return -1; } /* Parse both interfaces and addresses. */ for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) { ifm = (struct if_msghdr *) buf; if (ifm->ifm_type == RTM_IFINFO) { ifp = if_lookup_by_index (ifm->ifm_index); if (ifp) ifp->stats = ifm->ifm_data; } } /* Free sysctl buffer. */ XFREE (MTYPE_TMP, ref); return 0; }
struct ospf6_interface * ospf6_interface_lookup_by_ifindex (int ifindex) { struct ospf6_interface *oi; struct interface *ifp; ifp = if_lookup_by_index (ifindex); if (ifp == NULL) return (struct ospf6_interface *) NULL; oi = (struct ospf6_interface *) ifp->info; return oi; }
int irdp_read_raw(struct thread *r) { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; char buf[IRDP_RX_BUF]; int ret, ifindex = 0; int irdp_sock = THREAD_FD(r); t_irdp_raw = thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock); ret = irdp_recvmsg(irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex); if (ret < 0) zlog_warn("IRDP: RX Error length = %d", ret); ifp = if_lookup_by_index(ifindex); if (!ifp) return ret; zi = ifp->info; if (!zi) return ret; irdp = &zi->irdp; if (!irdp) return ret; if (!(irdp->flags & IF_ACTIVE)) { if (irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name); return 0; } if (irdp->flags & IF_DEBUG_PACKET) { int i; zlog_debug("IRDP: RX (idx %d) ", ifindex); for (i = 0; i < ret; i++) zlog_debug("IRDP: RX %x ", buf[i] & 0xFF); } parse_irdp_packet(buf, ret, ifp); return ret; }
/* Allocate a new internal interface index * This works done from the top so that %d macros * print a - sign! */ static unsigned int if_new_intern_ifindex (void) { /* Start here so that first one assigned is 0xFFFFFFFF */ static unsigned int ifindex = IFINDEX_INTERNBASE + 1; for (;;) { ifindex--; if ( ifindex <= IFINDEX_INTERNBASE ) ifindex = 0xFFFFFFFF; if (if_lookup_by_index(ifindex) == NULL) return ifindex; } }
int if_address_add_v6(struct ctrl_client * ctrl_client, struct rfpbuf * buffer) { const struct rfp_ipv6_address * address = buffer->data; struct interface * ifp = if_lookup_by_index(ctrl_client->if_list, address->ifindex); struct connected * ifc; struct prefix p; memcpy(&p.u.prefix, &address->p, 16); p.prefixlen = address->prefixlen; p.family = AF_INET6; ifc = connected_add_by_prefix(ifp, &p, NULL); if(ifc == NULL) return 1; if(IS_OSPF6_SIBLING_DEBUG_MSG) { char prefix_str[INET6_ADDRSTRLEN+3]; // three extra chars for slash + two digits if(prefix2str(ifc->address, prefix_str, INET6_ADDRSTRLEN) != 1) { zlog_debug("v6 addr: %s", prefix_str, ifc->address->prefixlen); } } // check here for: // 1. prefix matches // 2. extract hostnum from host portion of address // 3. if hostnum matches, this is the internal interface that should be recorded char inter_target_str[INET6_ADDRSTRLEN+3]; // three extra chars for slash + two digits struct prefix inter_target_p; sprintf(inter_target_str, "2001:db8:beef:10::%x/64", ctrl_client->hostnum); str2prefix(inter_target_str, &inter_target_p); // link up the internal connected address with a pointer at ctrl_client if(prefix_same(ifc->address, &inter_target_p)) { ctrl_client->inter_con = ifc; } // since connected address is AF_INET6, needs to be updated ospf6_interface_connected_route_update(ifc->ifp); return 0; }
int nhrp_route_read(ZAPI_CALLBACK_ARGS) { struct zapi_route api; struct zapi_nexthop *api_nh; struct interface *ifp = NULL; union sockunion nexthop_addr; char buf[2][PREFIX_STRLEN]; int added; if (zapi_route_decode(zclient->ibuf, &api) < 0) return -1; /* we completely ignore srcdest routes for now. */ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) return 0; sockunion_family(&nexthop_addr) = AF_UNSPEC; if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { api_nh = &api.nexthops[0]; nexthop_addr.sa.sa_family = api.prefix.family; switch (nexthop_addr.sa.sa_family) { case AF_INET: nexthop_addr.sin.sin_addr = api_nh->gate.ipv4; break; case AF_INET6: nexthop_addr.sin6.sin6_addr = api_nh->gate.ipv6; break; } if (api_nh->ifindex != IFINDEX_INTERNAL) ifp = if_lookup_by_index(api_nh->ifindex, VRF_DEFAULT); } added = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD); debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s", added ? "add" : "del", prefix2str(&api.prefix, buf[0], sizeof buf[0]), sockunion2str(&nexthop_addr, buf[1], sizeof buf[1]), ifp ? ifp->name : "(none)"); nhrp_route_update_zebra(&api.prefix, &nexthop_addr, ifp); nhrp_shortcut_prefix_change(&api.prefix, !added); return 0; }
/* Interface adding function */ static int ifan_read (struct if_announcemsghdr *ifan) { struct interface *ifp; ifp = if_lookup_by_index (ifan->ifan_index); if (ifp) assert ( (ifp->ifindex == ifan->ifan_index) || (ifp->ifindex == IFINDEX_INTERNAL) ); if ( (ifp == NULL) || ((ifp->ifindex == IFINDEX_INTERNAL) && (ifan->ifan_what == IFAN_ARRIVAL)) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating interface for ifindex %d, name %s", __func__, ifan->ifan_index, ifan->ifan_name); /* Create Interface */ ifp = if_get_by_name_len(ifan->ifan_name, strnlen(ifan->ifan_name, sizeof(ifan->ifan_name))); ifp->ifindex = ifan->ifan_index; if_add_update (ifp); } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) if_delete_update (ifp); if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: interface %s index %d", __func__, ifan->ifan_name, ifan->ifan_index); return 0; }
int if_address_add_v4(struct ctrl_client * ctrl_client, struct rfpbuf * buffer) { const struct rfp_ipv4_address * address = buffer->data; struct interface * ifp = if_lookup_by_index(ctrl_client->if_list, address->ifindex); struct connected * ifc; struct prefix p; memcpy(&p.u.prefix, &address->p, 4); p.prefixlen = address->prefixlen; p.family = AF_INET; ifc = connected_add_by_prefix(ifp, &p, NULL); if(ifc == NULL) return 1; // struct connected * ifc = calloc(1, sizeof(struct connected)); // ifc->address = calloc(1, sizeof(struct prefix)); // memcpy(&ifc->address->u.prefix, &address->p, 4); // ifc->address->prefixlen = address->prefixlen; // ifc->address->family = AF_INET; // list_init(&ifc->node); if(IS_OSPF6_SIBLING_DEBUG_MSG) { char prefix_str[INET_ADDRSTRLEN]; if(inet_ntop(AF_INET, &(p.u.prefix4.s_addr), prefix_str, INET_ADDRSTRLEN) != 1) { zlog_debug("v4 addr: %s/%d", prefix_str, ifc->address->prefixlen); } } // add addresss to list of connected // list_push_back(&ifp->connected, &ifc->node); // ifc->ifp = ifp; return 0; }
struct interface * zebra_interface_link_params_read (struct stream *s) { struct if_link_params *iflp; uint32_t ifindex = stream_getl (s); struct interface *ifp = if_lookup_by_index (ifindex); if (ifp == NULL || s == NULL) { zlog_err ("%s: unknown ifindex %u, shouldn't happen", __func__, ifindex); return NULL; } if ((iflp = if_link_params_get (ifp)) == NULL) return NULL; link_params_set_value(s, iflp); return ifp; }
/* Lookup interface by interface's IP address or interface index. */ static struct interface * ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) { struct prefix_ipv4 p; struct route_node *rn; struct interface *ifp; if (addr) { p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = *addr; rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); if (! rn) return NULL; ifp = rn->info; route_unlock_node (rn); return ifp; } else return if_lookup_by_index(ifindex); }
/* * Search the network interface and gateway address to forward the packet. * Return also the IP adress of the interface, */ if_t *route_lookup (uint32_t ip) { struct rib * rib_new; struct in_addr addr; if_t *outif = NULL; addr.s_addr = ip; rib_new = rib_match_ipv4 (addr); if (!rib_new) { /*Temp Fix*/ if ((ip & 0x000007f) == 0x7f) return get_loopback_if (); return NULL; } outif = if_lookup_by_index (rib_new->nexthop->ifindex); if ((outif->ip_addr.addr == ip) || ((ip & 0x000007f) == 0x7f)) { outif = get_loopback_if (); } return outif; }
/* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void set_ifindex(struct interface *ifp, unsigned int ifi_index) { struct interface *oifp; if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp)) { if (ifi_index == IFINDEX_INTERNAL) zlog_err("Netlink is setting interface %s ifindex to reserved " "internal value %u", ifp->name, ifi_index); else { if (IS_DEBUG_HA(kroute, KROUTE)) zlog_debug("interface index %d was renamed from %s to %s", ifi_index, oifp->name, ifp->name); if (if_is_up(oifp)) zlog_err("interface rename detected on up interface: index %d " "was renamed from %s to %s, results are uncertain!", ifi_index, oifp->name, ifp->name); if_delete_update(oifp); } } ifp->ifindex = ifi_index; }
/* Interface adding function called from interface_list. */ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp; struct sockaddr_dl *sdl = NULL; sdl = (struct sockaddr_dl *)(ifm + 1); /* Use sdl index. */ ifp = if_lookup_by_index (ifm->ifm_index); if (ifp == NULL) { /* Check interface's address.*/ if (! (ifm->ifm_addrs & RTA_IFP)) { zlog_warn ("There must be RTA_IFP address for ifindex %d\n", ifm->ifm_index); return -1; } ifp = if_create (); strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen); ifp->ifindex = ifm->ifm_index; ifp->flags = ifm->ifm_flags; #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); /* Fetch hardware address. */ if (sdl->sdl_family != AF_LINK) { zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK"); return -1; } memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); if_add_update (ifp); } else { /* There is a case of promisc, allmulti flag modification. */ if (if_is_up (ifp)) { ifp->flags = ifm->ifm_flags; if (! if_is_up (ifp)) if_down (ifp); } else { ifp->flags = ifm->ifm_flags; if (if_is_up (ifp)) if_up (ifp); } } #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); return 0; }
static int ldp_zebra_read_ipv4(int cmd, struct zclient *client, zebra_size_t length) { struct prefix_ipv4 prefix; struct zapi_ipv4 api; int i = 0; int j; struct mpls_nexthop nexthop[8]; struct ldp *ldp = ldp_get(); struct mpls_fec fec; struct stream *s; struct in_addr tmp; memset(&api,0,sizeof(api)); memset(nexthop,0,sizeof(nexthop)); s = client->ibuf; zapi_ipv4_read (s, length, &api, &prefix); zlog_info("route %s/%d", inet_ntoa(prefix.prefix), prefix.prefixlen); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { for (i = 0; i < api.nexthop_num; i++) { if (api.type == ZEBRA_ROUTE_CONNECT) { nexthop[i].attached = MPLS_BOOL_TRUE; zlog_info("\tattached"); } nexthop[i].ip.type = MPLS_FAMILY_IPV4; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) nexthop[i].distance = api.message; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) nexthop[i].metric = api.metric; if (CHECK_FLAG (api.nexthop[i].type, ZEBRA_NEXTHOP_IPV4)) { nexthop[i].ip.u.ipv4 = ntohl(api.nexthop[i].gw.ipv4.s_addr); nexthop[i].type |= MPLS_NH_IP; tmp.s_addr = htonl(nexthop[i].ip.u.ipv4); zlog_info("\tnexthop %s", inet_ntoa(tmp)); } if (CHECK_FLAG (api.nexthop[i].type, ZEBRA_NEXTHOP_IFINDEX)) { nexthop[i].if_handle = if_lookup_by_index(api.nexthop[i].intf.index); if (nexthop[i].if_handle) { nexthop[i].type |= MPLS_NH_IF; zlog_info("\tifindex %d", nexthop[i].if_handle->ifindex); } } } } zebra_prefix2mpls_fec((struct prefix*)&prefix, &fec); for (j = 0; j < i; j++) { if (cmd == ZEBRA_IPV4_ROUTE_ADD) { zlog_info("\tadd"); if ((ldp_cfg_fec_get(ldp->h, &fec, 0) != MPLS_SUCCESS) || (fec.is_route == MPLS_BOOL_FALSE)) { if (ldp_cfg_fec_set(ldp->h, &fec, LDP_CFG_ADD) != MPLS_SUCCESS) { MPLS_ASSERT(0); } } if (ldp_cfg_fec_nexthop_get(ldp->h, &fec, &nexthop[j], LDP_FEC_CFG_BY_INDEX) != MPLS_SUCCESS) { if (ldp_cfg_fec_nexthop_set(ldp->h, &fec, &nexthop[j], LDP_CFG_ADD|LDP_FEC_CFG_BY_INDEX) != MPLS_SUCCESS) { MPLS_ASSERT(0); } } else { /* * already exists ... looks like we can get the same route sent * to us twice ... multiple protocols? MPLS_ASSERT(0); */ } } else { zlog_info("\tdelete"); if ((ldp_cfg_fec_get(ldp->h, &fec, 0) == MPLS_SUCCESS) && (fec.is_route == MPLS_BOOL_TRUE)) { if (ldp_cfg_fec_nexthop_get(ldp->h, &fec, &nexthop[j], LDP_FEC_CFG_BY_INDEX) == MPLS_SUCCESS) { if (ldp_cfg_fec_nexthop_set(ldp->h, &fec, &nexthop[j], LDP_FEC_CFG_BY_INDEX|LDP_CFG_DEL| LDP_FEC_NEXTHOP_CFG_BY_INDEX) != MPLS_SUCCESS) { MPLS_ASSERT(0); } } else { MPLS_ASSERT(0); } if (ldp_cfg_fec_set(ldp->h, &fec, LDP_CFG_DEL|LDP_FEC_CFG_BY_INDEX) != MPLS_SUCCESS) { MPLS_ASSERT(0); } } else { MPLS_ASSERT(0); } } } return 0; }
/* Interface function for the kernel routing table updates. Support * for RTM_CHANGE will be needed. * Exported only for rt_socket.c */ int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric) { int ret; caddr_t pnt; struct interface *ifp; /* Sequencial number of routing message. */ static int msg_seq = 0; /* Struct of rt_msghdr and buffer for storing socket's data. */ struct { struct rt_msghdr rtm; char buf[512]; } msg; if (routing_sock < 0) return ZEBRA_ERR_EPERM; /* Clear and set rt_msghdr values */ memset (&msg, 0, sizeof (struct rt_msghdr)); msg.rtm.rtm_version = RTM_VERSION; msg.rtm.rtm_type = message; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_flags = RTF_UP; msg.rtm.rtm_index = index; if (metric != 0) { msg.rtm.rtm_rmx.rmx_hopcount = metric; msg.rtm.rtm_inits |= RTV_HOPCOUNT; } ifp = if_lookup_by_index (index); if (gate && message == RTM_ADD) msg.rtm.rtm_flags |= RTF_GATEWAY; /* When RTF_CLONING is unavailable on BSD, should we set some * other flag instead? */ #ifdef RTF_CLONING if (! gate && message == RTM_ADD && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; #endif /* RTF_CLONING */ /* If no protocol specific gateway is specified, use link address for gateway. */ if (! gate) { if (!ifp) { char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255"; if (dest) inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN); if (mask) inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN); zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d", __func__, dest_buf, mask_buf, index); return -1; } gate = (union sockunion *) & ifp->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); /* Additional flags. */ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; if (zebra_flags & ZEBRA_FLAG_REJECT) msg.rtm.rtm_flags |= RTF_REJECT; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP ((X)->sa.sa_len); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = SAROUNDUP (X); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ pnt = (caddr_t) msg.buf; /* Write each socket data into rtm message buffer */ SOCKADDRSET (dest, RTA_DST); SOCKADDRSET (gate, RTA_GATEWAY); SOCKADDRSET (mask, RTA_NETMASK); msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); if (ret != msg.rtm.rtm_msglen) { if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; if (errno == ESRCH) return ZEBRA_ERR_RTNOEXIST; zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno); return ZEBRA_ERR_KERNEL; } return ZEBRA_ERR_NOERROR; }
/* 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; }
/* * Handle struct if_msghdr obtained from reading routing socket or * sysctl (from interface_list). There may or may not be sockaddrs * present after the header. */ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp = NULL; char ifname[IFNAMSIZ]; short ifnlen = 0; caddr_t *cp; /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; /* paranoia: sanity check structure */ if (ifm->ifm_msglen < sizeof(struct if_msghdr)) { zlog_err ("ifm_read: ifm->ifm_msglen %d too short\n", ifm->ifm_msglen); return -1; } /* * Check for a sockaddr_dl following the message. First, point to * where a socakddr might be if one follows the message. */ cp = (void *)(ifm + 1); #ifdef SUNOS_5 /* * XXX This behavior should be narrowed to only the kernel versions * for which the structures returned do not match the headers. * * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions * is 12 bytes larger than the 32 bit version. */ if (((struct sockaddr *) cp)->sa_family == AF_UNSPEC) cp = cp + 12; #endif RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp); RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp); RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen); RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)")); /* * Look up on ifindex first, because ifindices are the primary handle for * interfaces across the user/kernel boundary, for most systems. (Some * messages, such as up/down status changes on NetBSD, do not include a * sockaddr_dl). */ if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL ) { /* we have an ifp, verify that the name matches as some systems, * eg Solaris, have a 1:many association of ifindex:ifname * if they dont match, we dont have the correct ifp and should * set it back to NULL to let next check do lookup by name */ if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ifp name %s doesnt match sdl name %s", __func__, ifp->name, ifname); ifp = NULL; } } /* * If we dont have an ifp, try looking up by name. Particularly as some * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname * is therefore our unique handle to that interface. * * Interfaces specified in the configuration file for which the ifindex * has not been determined will have ifindex == IFINDEX_INTERNAL, and such * interfaces are found by this search, and then their ifindex values can * be filled in. */ if ( (ifp == NULL) && ifnlen) ifp = if_lookup_by_name (ifname); /* * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL), * create or fill in an interface. */ if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL)) { /* * To create or fill in an interface, a sockaddr_dl (via * RTA_IFP) is required. */ if (!ifnlen) { zlog_warn ("Interface index %d (new) missing ifname\n", ifm->ifm_index); return -1; } #ifndef RTM_IFANNOUNCE /* Down->Down interface should be ignored here. * See further comment below. */ if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP)) return 0; #endif /* !RTM_IFANNOUNCE */ if (ifp == NULL) { /* Interface that zebra was not previously aware of, so create. */ ifp = if_create (ifname, ifnlen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating ifp for ifindex %d", __func__, ifm->ifm_index); } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d", __func__, ifp->name, ifp->ifindex); /* * Fill in newly created interface structure, or larval * structure with ifindex IFINDEX_INTERNAL. */ ifp->ifindex = ifm->ifm_index; #ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_LINK_DETECT */ if_flags_update (ifp, ifm->ifm_flags); #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); if_add_update (ifp); } else /* * Interface structure exists. Adjust stored flags from * notification. If interface has up->down or down->up * transition, call state change routines (to adjust routes, * notify routing daemons, etc.). (Other flag changes are stored * but apparently do not trigger action.) */ { if (ifp->ifindex != ifm->ifm_index) { zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, " "ifm index %d", __func__, ifp->name, ifp->ifindex, ifm->ifm_index); return -1; } #ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_LINK_DETECT */ /* update flags and handle operative->inoperative transition, if any */ if_flags_update (ifp, ifm->ifm_flags); #ifndef RTM_IFANNOUNCE if (!if_is_up (ifp)) { /* No RTM_IFANNOUNCE on this platform, so we can never * distinguish between ~IFF_UP and delete. We must presume * it has been deleted. * Eg, Solaris will not notify us of unplumb. * * XXX: Fixme - this should be runtime detected * So that a binary compiled on a system with IFANNOUNCE * will still behave correctly if run on a platform without */ if_delete_update (ifp); } #endif /* RTM_IFANNOUNCE */ if (if_is_up (ifp)) { #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); } } #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: interface %s index %d", __func__, ifp->name, ifp->ifindex); return 0; }
int babel_filter(int output, const unsigned char *prefix, unsigned short plen, unsigned int ifindex) { struct interface *ifp = if_lookup_by_index(ifindex); babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL; struct prefix p; struct distribute *dist; struct access_list *alist; struct prefix_list *plist; int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN; int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) uchar_to_inaddr(&p.u.prefix4, prefix); #ifdef HAVE_IPV6 else uchar_to_in6addr(&p.u.prefix6, prefix); #endif if (babel_ifp != NULL && babel_ifp->list[filter]) { if (access_list_apply (babel_ifp->list[filter], &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", #ifdef HAVE_IPV6 p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), #else inet_ntoa(p.u.prefix4), #endif p.prefixlen); return INFINITY; } } if (babel_ifp != NULL && babel_ifp->prefix[filter]) { if (prefix_list_apply (babel_ifp->prefix[filter], &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", #ifdef HAVE_IPV6 p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), #else inet_ntoa(p.u.prefix4), #endif p.prefixlen); return INFINITY; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[distribute]) { alist = access_list_lookup (AFI_IP6, dist->list[distribute]); if (alist) { if (access_list_apply (alist, &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", #ifdef HAVE_IPV6 p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), #else inet_ntoa(p.u.prefix4), #endif p.prefixlen); return INFINITY; } } } if (dist->prefix[distribute]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); if (plist) { if (prefix_list_apply (plist, &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", #ifdef HAVE_IPV6 p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), #else inet_ntoa(p.u.prefix4), #endif p.prefixlen); return INFINITY; } } } } 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; }
struct connected * zebra_interface_address_read (int type, struct stream *s) { unsigned int ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; int family; int plen; u_char ifc_flags; memset (&p, 0, sizeof(p)); memset (&d, 0, sizeof(d)); /* Get interface index. */ ifindex = stream_getl (s); /* Lookup index. */ ifp = if_lookup_by_index (ifindex); if (ifp == NULL) { zlog_warn ("zebra_interface_address_read(%s): " "Can't find interface by ifindex: %d ", (type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"), ifindex); return NULL; } /* Fetch flag. */ ifc_flags = stream_getc (s); /* Fetch interface address. */ family = p.family = stream_getc (s); plen = prefix_blen (&p); stream_get (&p.u.prefix, s, plen); p.prefixlen = stream_getc (s); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); d.family = family; if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* 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; if (ifc->destination) ifc->destination->prefixlen = ifc->address->prefixlen; else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { /* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */ char buf[BUFSIZ]; prefix2str (ifc->address, buf, sizeof(buf)); zlog_warn("warning: interface %s address %s " "with peer flag set, but no peer address!", ifp->name, buf); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } } } else { assert (type == ZEBRA_INTERFACE_ADDRESS_DELETE); ifc = connected_delete_by_prefix(ifp, &p); } return ifc; }
/* Interface function for the kernel routing table updates. Support for RTM_CHANGE will be needed. */ int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric) { int ret; caddr_t pnt; struct interface *ifp; struct sockaddr_in tmp_gate; #ifdef HAVE_IPV6 struct sockaddr_in6 tmp_gate6; #endif /* HAVE_IPV6 */ /* Sequencial number of routing message. */ static int msg_seq = 0; /* Struct of rt_msghdr and buffer for storing socket's data. */ struct { struct rt_msghdr rtm; char buf[512]; } msg; memset (&tmp_gate, 0, sizeof (struct sockaddr_in)); tmp_gate.sin_family = AF_INET; #ifdef HAVE_SIN_LEN tmp_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_SIN_LEN */ #ifdef HAVE_IPV6 memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6)); tmp_gate6.sin6_family = AF_INET6; #ifdef SIN6_LEN tmp_gate6.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ #endif /* HAVE_IPV6 */ if (routing_sock < 0) return ZEBRA_ERR_EPERM; /* Clear and set rt_msghdr values */ memset (&msg, 0, sizeof (struct rt_msghdr)); msg.rtm.rtm_version = RTM_VERSION; msg.rtm.rtm_type = message; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_flags = RTF_UP; msg.rtm.rtm_index = index; if (metric != 0) { msg.rtm.rtm_rmx.rmx_hopcount = metric; msg.rtm.rtm_inits |= RTV_HOPCOUNT; } ifp = if_lookup_by_index (index); if (gate && message == RTM_ADD) msg.rtm.rtm_flags |= RTF_GATEWAY; if (! gate && message == RTM_ADD && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; /* If no protocol specific gateway is specified, use link address for gateway. */ if (! gate) { if (!ifp) { zlog_warn ("no gateway found for interface index %d", index); return -1; } gate = (union sockunion *) & ifp->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); /* Additional flags. */ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; #ifdef HAVE_SIN_LEN #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP ((X)->sa.sa_len); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP (sizeof((X)->sa)); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #endif /* HAVE_SIN_LEN */ pnt = (caddr_t) msg.buf; /* Write each socket data into rtm message buffer */ SOCKADDRSET (dest, RTA_DST); SOCKADDRSET (gate, RTA_GATEWAY); SOCKADDRSET (mask, RTA_NETMASK); msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); if (ret != msg.rtm.rtm_msglen) { if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; zlog_warn ("write : %s (%d)", strerror (errno), errno); return -1; } 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; }