int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb [IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *)RTA_DATA(tb[IFLA_IFNAME]); /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); ifp->ifindex = ifi->ifi_index; ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; /* If new link is added. */ if_add_update(ifp); } else { /* Interface status change. */ ifp->ifindex = ifi->ifi_index; ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; if (if_is_up (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (! if_is_up (ifp)) if_down (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_up (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", ifp->name); return 0; } if_delete_update (ifp); } 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; }
static int open_dlpi_dev(struct isis_circuit *circuit) { int fd = -1, unit, retval; char devpath[MAXPATHLEN]; dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl; ssize_t acklen; /* Only broadcast-type are supported at the moment */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn("%s: non-broadcast interface %s", __func__, circuit->interface->name); return ISIS_WARNING; } /* Try the vanity node first, if permitted */ if (getenv("DLPI_DEVONLY") == NULL) { (void)snprintf(devpath, sizeof(devpath), "/dev/net/%s", circuit->interface->name); fd = dlpiopen(devpath, &acklen); } /* Now try as an ordinary Style 1 node */ if (fd == -1) { (void)snprintf(devpath, sizeof(devpath), "/dev/%s", circuit->interface->name); unit = -1; fd = dlpiopen(devpath, &acklen); } /* If that fails, try again as Style 2 */ if (fd == -1) { char *cp; cp = devpath + strlen(devpath); while (--cp >= devpath && isdigit(*cp)) ; unit = strtol(cp, NULL, 0); *cp = '\0'; fd = dlpiopen(devpath, &acklen); /* If that too fails, then the device really doesn't exist */ if (fd == -1) { zlog_warn("%s: unknown interface %s", __func__, circuit->interface->name); return ISIS_WARNING; } /* Double check the DLPI style */ if (dia->dl_provider_style != DL_STYLE2) { zlog_warn( "open_dlpi_dev(): interface %s: %s is not style 2", circuit->interface->name, devpath); close(fd); return ISIS_WARNING; } /* If it succeeds, then we need to attach to the unit specified */ dlpiattach(fd, unit); /* Reget the information, as it may be different per node */ if ((acklen = dlpiinfo(fd)) == -1) { close(fd); return ISIS_WARNING; } } else { /* Double check the DLPI style */ if (dia->dl_provider_style != DL_STYLE1) { zlog_warn( "open_dlpi_dev(): interface %s: %s is not style 1", circuit->interface->name, devpath); close(fd); return ISIS_WARNING; } } /* Check that the interface we've got is the kind we expect */ if ((dia->dl_sap_length != 2 && dia->dl_sap_length != -2) || dia->dl_service_mode != DL_CLDLS || dia->dl_addr_length != ETHERADDRL + 2 || dia->dl_brdcst_addr_length != ETHERADDRL) { zlog_warn("%s: unsupported interface type for %s", __func__, circuit->interface->name); close(fd); return ISIS_WARNING; } switch (dia->dl_mac_type) { case DL_CSMACD: case DL_ETHER: case DL_100VG: case DL_100VGTPR: case DL_ETH_CSMA: case DL_100BT: break; default: zlog_warn("%s: unexpected mac type on %s: %lld", __func__, circuit->interface->name, (long long)dia->dl_mac_type); close(fd); return ISIS_WARNING; } circuit->sap_length = dia->dl_sap_length; /* * The local hardware address is something that should be provided by * way of * sockaddr_dl for the interface, but isn't on Solaris. We set it here * based * on DLPI's reported address to avoid roto-tilling the world. * (Note that isis_circuit_if_add on Solaris doesn't set the snpa.) * * Unfortunately, GLD is broken and doesn't provide the address after * attach, * so we need to be careful and use DL_PHYS_ADDR_REQ instead. */ if (dlpiaddr(fd, circuit->u.bc.snpa) == -1) { zlog_warn( "open_dlpi_dev(): interface %s: unable to get MAC address", circuit->interface->name); close(fd); return ISIS_WARNING; } /* Now bind to SAP 0. This gives us 802-type traffic. */ if (dlpibind(fd) == -1) { zlog_warn("%s: cannot bind SAP 0 on %s", __func__, circuit->interface->name); close(fd); return ISIS_WARNING; } /* * Join to multicast groups according to * 8.4.2 - Broadcast subnetwork IIH PDUs */ retval = 0; retval |= dlpimcast(fd, ALL_L1_ISS); retval |= dlpimcast(fd, ALL_ISS); retval |= dlpimcast(fd, ALL_L2_ISS); if (retval != 0) { zlog_warn("%s: unable to join multicast on %s", __func__, circuit->interface->name); close(fd); return ISIS_WARNING; } /* Push on the packet filter to avoid stray 802 packets */ if (ioctl(fd, I_PUSH, "pfmod") == 0) { struct packetfilt pfil; struct strioctl sioc; pfil.Pf_Priority = 0; pfil.Pf_FilterLen = sizeof(pf_filter) / sizeof(unsigned short); memcpy(pfil.Pf_Filter, pf_filter, sizeof(pf_filter)); /* pfmod does not support transparent ioctls */ sioc.ic_cmd = PFIOCSETF; sioc.ic_timout = 5; sioc.ic_len = sizeof(struct packetfilt); sioc.ic_dp = (char *)&pfil; if (ioctl(fd, I_STR, &sioc) == -1) zlog_warn("%s: could not perform PF_IOCSETF on %s", __func__, circuit->interface->name); } circuit->fd = fd; return ISIS_OK; }
/* Add connected IPv4 route to the interface. */ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad, const char *label) { struct prefix_ipv4 *p; struct connected *ifc; /* Make connected structure. */ ifc = connected_new(); ifc->ifp = ifp; ifc->flags = flags; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* Allocate new connected address. */ p = prefix_ipv4_new(); p->family = AF_INET; p->prefix = *addr; p->prefixlen = prefixlen; ifc->address = (struct prefix *)p; /* If there is broadcast or peer address. */ if (broad) { p = prefix_ipv4_new(); p->family = AF_INET; p->prefix = *broad; p->prefixlen = prefixlen; ifc->destination = (struct prefix *)p; /* validate the destination address */ if (CONNECTED_PEER(ifc)) { if (IPV4_ADDR_SAME(addr, broad)) zlog_warn ("warning: interface %s has same local and peer " "address %s, routing protocols may malfunction", ifp->name, inet_ntoa(*addr)); } 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 { if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { zlog_warn("warning: %s called for interface %s " "with peer flag set, but no peer address supplied", __func__, ifp->name); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } /* no broadcast or destination address was supplied */ if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp)) zlog_warn ("warning: PtP interface %s with addr %s/%d needs a " "peer address", ifp->name, inet_ntoa(*addr), prefixlen); } /* Label of this address. */ if (label) ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); /* For all that I know an IPv4 address is always ready when we receive * the notification. So it should be safe to set the REAL flag here. */ SET_FLAG(ifc->conf, ZEBRA_IFC_REAL); connected_update(ifp, ifc); }
/* * 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; }
/* Parse SMUX message. */ int smux_parse (char *ptr, size_t len) { /* This buffer we'll use for SOUT message. We could allocate it with malloc and save only static pointer/lenght, but IMHO static buffer is a faster solusion. */ static u_char sout_save_buff[SMUXMAXPKTSIZE]; static int sout_save_len = 0; int len_income = len; /* see note below: YYY */ u_char type; u_char rollback; rollback = ptr[2]; /* important only for SMUX_SOUT */ process_rest: /* see note below: YYY */ /* Parse SMUX message type and subsequent length. */ ptr = asn_parse_header (ptr, &len, &type); if (debug_smux) zlog_debug ("SMUX message received type: %d rest len: %ld", type, len); switch (type) { case SMUX_OPEN: /* Open must be not send from SNMP agent. */ zlog_warn ("SMUX_OPEN received: resetting connection."); return -1; break; case SMUX_RREQ: /* SMUX_RREQ message is invalid for us. */ zlog_warn ("SMUX_RREQ received: resetting connection."); return -1; break; case SMUX_SOUT: /* SMUX_SOUT message is now valied for us. */ if (debug_smux) zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit"); if (sout_save_len > 0) { smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT); sout_save_len = 0; } else zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len); if (len_income > 3) { /* YYY: this strange code has to solve the "slow peer" problem: When agent sends SMUX_SOUT message it doesn't wait any responce and may send some next message to subagent. Then the peer in 'smux_read()' will recieve from socket the 'concatenated' buffer, contaning both SMUX_SOUT message and the next one (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if the buffer is longer than 3 ( length of SMUX_SOUT ), we must process the rest of it. This effect may be observed if 'debug_smux' is set to '1' */ ptr++; len = len_income - 3; goto process_rest; } break; case SMUX_GETRSP: /* SMUX_GETRSP message is invalid for us. */ zlog_warn ("SMUX_GETRSP received: resetting connection."); return -1; break; case SMUX_CLOSE: /* Close SMUX connection. */ if (debug_smux) zlog_debug ("SMUX_CLOSE"); smux_parse_close (ptr, len); return -1; break; case SMUX_RRSP: /* This is response for register message. */ if (debug_smux) zlog_debug ("SMUX_RRSP"); smux_parse_rrsp (ptr, len); break; case SMUX_GET: /* Exact request for object id. */ if (debug_smux) zlog_debug ("SMUX_GET"); smux_parse_get (ptr, len, 1); break; case SMUX_GETNEXT: /* Next request for object id. */ if (debug_smux) zlog_debug ("SMUX_GETNEXT"); smux_parse_get (ptr, len, 0); break; case SMUX_SET: /* SMUX_SET is supported with some limitations. */ if (debug_smux) zlog_debug ("SMUX_SET"); /* save the data for future SMUX_SOUT */ memcpy (sout_save_buff, ptr, len); sout_save_len = len; smux_parse_set (ptr, len, RESERVE1); break; default: zlog_info ("Unknown type: %d", type); break; } return 0; }
static int sys_func_dl_prepare(int slot_id, uint64_t blk_start, uint64_t blk_num, uint32_t req_frag) { int ret; sys_ctx_t* ctx = &sys_ctx; int repo_num = ctx->vault->repo_num; size_t cache_sz = SYS_CACHE_SIZE; int i, j; int interlace_sz = SYS_INTERLACE_SIZE; sys_cache_t* file_cache = ctx->file_cache; assert(file_cache); assert(file_cache->data); // get slot_sz ssize_t slot_sz; if (file_cache->slot_id == slot_id ) { slot_sz = file_cache->slot_sz; } else { slot_sz = dfv_vault_get_slotsize(ctx->vault, slot_id); if (slot_sz < 0) { zlog_error(sys_zc, "bad file size: slot_id=%d", slot_id); return(SPKERR_BADRES); } } // request region uint64_t req_start = blk_start * SYS_CACHE_SIZE; uint64_t req_end = (blk_num>0)?(req_start + blk_num * SYS_CACHE_SIZE):slot_sz; // frag region uint64_t frag_start = req_start + (uint64_t)req_frag * CMI_MAX_FRAGSIZE; uint64_t frag_end = frag_start + CMI_MAX_FRAGSIZE; // check if region is valid if (frag_start > slot_sz) { zlog_error(sys_zc, "illegal frag_start: slot_id=%d, slot_sz=%zu, " "frag_start=%lu, req_frag=%u", slot_id, slot_sz, frag_start, req_frag); return(SPKERR_PARAM); } if (frag_end > slot_sz) { zlog_warn(sys_zc, "truncate frag: slot_id=%d, slot_sz=%zu, " "frag=%lu+%lu", slot_id, slot_sz, frag_start, frag_end); frag_end = slot_sz; } // check cache hit int cache_hit = 0; do { if (file_cache->slot_id != slot_id) { // slot not match break; } if (frag_start < file_cache->offset || frag_end > file_cache->offset + file_cache->len) { break; } cache_hit = 1; } while(0); if (cache_hit) { return(SPK_SUCCESS); } // do caching cache_sz = MIN(SYS_CACHE_SIZE, slot_sz - frag_start); size_t cache_sz_repo = cache_sz / repo_num; zlog_notice(sys_zc, "cache file: slot_id=%d, slot_sz=%zu, req_frag=%u, " "req=%lu+%lu, frag=%lu+%lu, cache_sz=%zu, blk=%lu+%lu", slot_id, slot_sz, req_frag, req_start, req_end-req_start, frag_start, frag_end-frag_start, cache_sz, blk_start, blk_num); struct dfv_file* file_ctx = NULL; void* file_buffer = memalign(SYS_INTERLACE_SIZE, cache_sz_repo); for (i=0; i<repo_num; i++) { struct dfv_repo * repo = ctx->vault->repo_tbl[i]; assert(repo); file_ctx = dfv_file_open(repo, slot_id, SPK_DIR_READ, NULL, 12+4*i); if (!file_ctx) { ret = SPKERR_BADRES; goto out; } ret = dfv_file_seek(file_ctx, frag_start / repo_num); if (ret) { goto out; } ssize_t read_sz = dfv_file_read(file_ctx, file_buffer, cache_sz_repo); if (read_sz != cache_sz_repo) { ret = SPKERR_BADRES; goto out; } dfv_file_close(file_ctx); file_ctx = NULL; // do interlace while copy data for (j=0; j<cache_sz_repo/interlace_sz; j++) { memcpy(file_cache->data+(j*repo_num+i)*interlace_sz, file_buffer+j*interlace_sz, interlace_sz); } } // cache done file_cache->slot_id = slot_id; file_cache->offset = frag_start; file_cache->len = cache_sz; file_cache->slot_sz = slot_sz; zlog_notice(sys_zc, "cache done: slot_id=%d, slot_sz=%lu, cache=%lu+%lu", slot_id, slot_sz, file_cache->offset, file_cache->len); ret = SPK_SUCCESS; out: if (file_ctx) { dfv_file_close(file_ctx); file_ctx = NULL; } SAFE_RELEASE(file_buffer); return(ret); }
/* Interface looking up using infamous SIOCGIFCONF. */ static int interface_list_ioctl (void) { int ret; int sock; #define IFNUM_BASE 32 int ifnum; struct ifreq *ifreq; struct ifconf ifconf; struct interface *ifp; int n; int lastlen; /* Normally SIOCGIFCONF works with AF_INET socket. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno)); return -1; } /* Set initial ifreq count. This will be double when SIOCGIFCONF fail. Solaris has SIOCGIFNUM. */ #ifdef SIOCGIFNUM ret = ioctl (sock, SIOCGIFNUM, &ifnum); if (ret < 0) ifnum = IFNUM_BASE; else ifnum++; #else ifnum = IFNUM_BASE; #endif /* SIOCGIFNUM */ ifconf.ifc_buf = NULL; lastlen = 0; /* Loop until SIOCGIFCONF success. */ for (;;) { ifconf.ifc_len = sizeof (struct ifreq) * ifnum; ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); ret = ioctl(sock, SIOCGIFCONF, &ifconf); if (ret < 0) { zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno)); goto end; } /* Repeatedly get info til buffer fails to grow. */ if (ifconf.ifc_len > lastlen) { lastlen = ifconf.ifc_len; ifnum += 10; continue; } /* Success. */ break; } /* Allocate interface. */ ifreq = ifconf.ifc_req; #ifdef OPEN_BSD for (n = 0; n < ifconf.ifc_len; ) { int size; ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n); ifp = if_get_by_name_len(ifreq->ifr_name, strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name))); if_add_update (ifp); size = ifreq->ifr_addr.sa_len; if (size < sizeof (ifreq->ifr_addr)) size = sizeof (ifreq->ifr_addr); size += sizeof (ifreq->ifr_name); n += size; } #else for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) { ifp = if_get_by_name_len(ifreq->ifr_name, strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name))); if_add_update (ifp); ifreq++; } #endif /* OPEN_BSD */ end: close (sock); XFREE (MTYPE_TMP, ifconf.ifc_buf); return ret; }
static int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); #ifdef IFLA_WIRELESS /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_DEBUG_HA(kroute, KROUTE)) zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); return 0; } #endif /* IFLA_WIRELESS */ if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *) RTA_DATA (tb[IFLA_IFNAME]); /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || !CHECK_FLAG (ifp->status, KROUTE_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; netlink_interface_update_hw_addr (tb, ifp); /* If new link is added. */ if_add_update (ifp); } else { /* Interface status change. */ set_ifindex(ifp, ifi->ifi_index); ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; netlink_interface_update_hw_addr (tb, ifp); if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (!if_is_operative (ifp)) if_down (ifp); else /* Must notify client daemons of new interface status. */ kroute_interface_up_update (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_operative (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", name); return 0; } if_delete_update (ifp); } return 0; }
void pim_if_addr_add(struct connected *ifc) { struct pim_interface *pim_ifp; struct interface *ifp; struct in_addr ifaddr; zassert(ifc); ifp = ifc->ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) return; if (!if_is_operative(ifp)) return; /* if (PIM_DEBUG_ZEBRA) */ { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d connected IP address %s %s", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } ifaddr = ifc->address->u.prefix4; detect_address_change(ifp, 0, __PRETTY_FUNCTION__); if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp); } } /* igmp */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { /* Interface has a valid primary address ? */ if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { if (pim_sock_add(ifp)) { zlog_warn("Failure creating PIM socket for interface %s", ifp->name); } } } } /* pim */ if (PIM_MROUTE_IS_ENABLED) { /* PIM or IGMP is enabled on interface, and there is at least one address assigned, then try to create a vif_index. */ if (pim_ifp->mroute_vif_index < 0) { pim_if_add_vif(ifp); } } }
/* 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 pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (!pim_ifp->igmp_join_list) { pim_ifp->igmp_join_list = list_new(); if (!pim_ifp->igmp_join_list) { zlog_err("%s %s: failure: igmp_join_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return -2; } pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free; } ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); if (ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -3; } ij = igmp_join_new(ifp, group_addr, source_addr); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -4; } { char group_str[100]; char source_str[100]; pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ifp->name); } return 0; }
static int open_bpf_dev (struct isis_circuit *circuit) { int i = 0, fd; char bpfdev[128]; struct ifreq ifr; u_int16_t blen; int true = 1, false = 0; struct timeval timeout; struct bpf_program bpf_prog; do { (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++); fd = open (bpfdev, O_RDWR); } while (fd < 0 && errno == EBUSY); if (fd < 0) { zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s", safe_strerror (errno)); return ISIS_WARNING; } zlog_debug ("Opened BPF device %s", bpfdev); memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name)); if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0) { zlog_warn ("open_bpf_dev(): failed to bind to interface: %s", safe_strerror (errno)); return ISIS_WARNING; } if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0) { zlog_warn ("failed to get BPF buffer len"); blen = circuit->interface->mtu; } readblen = blen; if (readbuff == NULL) readbuff = malloc (blen); zlog_debug ("BPF buffer len = %u", blen); /* BPF(4): reads return immediately upon packet reception. * Otherwise, a read will block until either the kernel * buffer becomes full or a timeout occurs. */ if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & true) < 0) { zlog_warn ("failed to set BPF dev to immediate mode"); } #ifdef BIOCSSEESENT /* * We want to see only incoming packets */ if (ioctl (fd, BIOCSSEESENT, (caddr_t) & false) < 0) { zlog_warn ("failed to set BPF dev to incoming only mode"); } #endif /* * ...but all of them */ if (ioctl (fd, BIOCPROMISC, (caddr_t) & true) < 0) { zlog_warn ("failed to set BPF dev to promiscuous mode"); } /* * If the buffer length is smaller than our mtu, lets try to increase it */ if (blen < circuit->interface->mtu) { if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0) { zlog_warn ("failed to set BPF buffer len (%u to %u)", blen, circuit->interface->mtu); } } /* * Set a timeout parameter - hope this helps select() */ timeout.tv_sec = 600; timeout.tv_usec = 0; if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0) { zlog_warn ("failed to set BPF device timeout"); } /* * And set the filter */ memset (&bpf_prog, 0, sizeof (struct bpf_program)); bpf_prog.bf_len = 8; bpf_prog.bf_insns = &(llcfilter[0]); if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0) { zlog_warn ("open_bpf_dev(): failed to install filter: %s", safe_strerror (errno)); return ISIS_WARNING; } assert (fd > 0); circuit->fd = fd; return ISIS_OK; }
static int open_packet_socket (struct isis_circuit *circuit) { struct sockaddr_ll s_addr; int fd, retval = ISIS_OK; fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL)); if (fd < 0) { zlog_warn ("open_packet_socket(): socket() failed %s", safe_strerror (errno)); return ISIS_WARNING; } /* * Bind to the physical interface */ memset (&s_addr, 0, sizeof (struct sockaddr_ll)); s_addr.sll_family = AF_PACKET; s_addr.sll_protocol = htons (ETH_P_ALL); s_addr.sll_ifindex = circuit->interface->ifindex; if (bind (fd, (struct sockaddr *) (&s_addr), sizeof (struct sockaddr_ll)) < 0) { zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno)); return ISIS_WARNING; } circuit->fd = fd; if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* * Join to multicast groups * according to * 8.4.2 - Broadcast subnetwork IIH PDUs * FIXME: is there a case only one will fail?? */ if (circuit->circuit_is_type & IS_LEVEL_1) { /* joining ALL_L1_ISS */ retval = isis_multicast_join (circuit->fd, 1, circuit->interface->ifindex); /* joining ALL_ISS */ retval = isis_multicast_join (circuit->fd, 3, circuit->interface->ifindex); } if (circuit->circuit_is_type & IS_LEVEL_2) /* joining ALL_L2_ISS */ retval = isis_multicast_join (circuit->fd, 2, circuit->interface->ifindex); } else { retval = isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex); } return retval; }
/* This function (unlike other buffer_flush* functions above) is designed to work with non-blocking sockets. It does not attempt to write out all of the queued data, just a "big" chunk. It returns 0 if it was able to empty out the buffers completely, 1 if more flushing is required later, or -1 on a fatal write error. */ buffer_status_t buffer_flush_available(struct buffer *b, int fd) { /* These are just reasonable values to make sure a significant amount of data is written. There's no need to go crazy and try to write it all in one shot. */ #ifdef IOV_MAX #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX) #else #define MAX_CHUNKS 16 #endif #define MAX_FLUSH 131072 struct buffer_data *d; size_t written; struct iovec iov[MAX_CHUNKS]; size_t iovcnt = 0; size_t nbyte = 0; for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH); d = d->next, iovcnt++) { iov[iovcnt].iov_base = d->data+d->sp; nbyte += (iov[iovcnt].iov_len = d->cp-d->sp); } if (!nbyte) /* No data to flush: should we issue a warning message? */ return BUFFER_EMPTY; /* only place where written should be sign compared */ if ((ssize_t)(written = writev(fd,iov,iovcnt)) < 0) { if (ERRNO_IO_RETRY(errno)) /* Calling code should try again later. */ return BUFFER_PENDING; zlog_warn("%s: write error on fd %d: %s", __func__, fd, safe_strerror(errno)); return BUFFER_ERROR; } /* Free printed buffer data. */ while (written > 0) { struct buffer_data *d; if (!(d = b->head)) { zlog_err("%s: corruption detected: buffer queue empty, " "but written is %lu", __func__, (u_long)written); break; } if (written < d->cp-d->sp) { d->sp += written; return BUFFER_PENDING; } written -= (d->cp-d->sp); if (!(b->head = d->next)) b->tail = NULL; BUFFER_DATA_FREE(d); } return b->head ? BUFFER_PENDING : BUFFER_EMPTY; #undef MAX_CHUNKS #undef MAX_FLUSH }
static int netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) { zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); return 0; }
int smux_socket () { int ret; #ifdef HAVE_IPV6 struct addrinfo hints, *res0, *res; int gai; #else struct sockaddr_in serv; struct servent *sp; #endif int sock = 0; #ifdef HAVE_IPV6 memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; gai = getaddrinfo(NULL, "smux", &hints, &res0); if (gai == EAI_SERVICE) { char servbuf[NI_MAXSERV]; sprintf(servbuf,"%d",SMUX_PORT_DEFAULT); servbuf[sizeof (servbuf) - 1] = '\0'; gai = getaddrinfo(NULL, servbuf, &hints, &res0); } if (gai) { zlog_warn("Cannot locate loopback service smux"); return -1; } for(res=res0; res; res=res->ai_next) { if (res->ai_family != AF_INET #ifdef HAVE_IPV6 && res->ai_family != AF_INET6 #endif /* HAVE_IPV6 */ ) continue; sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) continue; sockopt_reuseaddr (sock); sockopt_reuseport (sock); ret = connect (sock, res->ai_addr, res->ai_addrlen); if (ret < 0) { close(sock); sock = -1; continue; } break; } freeaddrinfo(res0); if (sock < 0) zlog_warn ("Can't connect to SNMP agent with SMUX"); #else sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { zlog_warn ("Can't make socket for SNMP"); return -1; } memset (&serv, 0, sizeof (struct sockaddr_in)); serv.sin_family = AF_INET; #ifdef HAVE_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_SIN_LEN */ sp = getservbyname ("smux", "tcp"); if (sp != NULL) serv.sin_port = sp->s_port; else serv.sin_port = htons (SMUX_PORT_DEFAULT); serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sockopt_reuseaddr (sock); sockopt_reuseport (sock); ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in)); if (ret < 0) { close (sock); smux_sock = -1; zlog_warn ("Can't connect to SNMP agent with SMUX"); return -1; } #endif return sock; }
/* Execute NSM event process. */ int ospf_nsm_event (struct thread *thread) { int event; int next_state; struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); event = THREAD_VAL (thread); if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), ospf_nsm_event_str [event]); next_state = NSM [nbr->state][event].next_state; /* Call function. */ if (NSM [nbr->state][event].func != NULL) { int func_state = (*(NSM [nbr->state][event].func))(nbr); if (NSM [nbr->state][event].next_state == NSM_DependUpon) next_state = func_state; else if (func_state) { /* There's a mismatch between the FSM tables and what an FSM * action/state-change function returned. State changes which * do not have conditional/DependUpon next-states should not * try set next_state. */ zlog_warn ("NSM[%s:%s]: %s (%s): " "Warning: action tried to change next_state to %s", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), ospf_nsm_event_str [event], LOOKUP (ospf_nsm_state_msg, func_state)); } } assert (next_state != NSM_DependUpon); /* If state is changed. */ if (next_state != nbr->state) { nsm_notice_state_change (nbr, next_state, event); nsm_change_state (nbr, next_state); } /* Make sure timer is set. */ nsm_timer_set (nbr); /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor * is deleted. * * Rather than encode knowledge here of which events lead to NBR * delete, we take our cue from the NSM table, via the dummy * 'Deleted' neighbour state. */ if (nbr->state == NSM_Deleted) ospf_nbr_delete (nbr); return 0; }
static int __sys_job_do_record(sys_wkr_ctx_t* wkr_ctx, IPS_EPID src_id, int pc_id, size_t ips_sec_sz, dfv_slot_def_t* slot_def, dfv_slice_def_t* slice_def) { int ret = -1; #ifdef ARCH_ppc64 struct ips_pcctx* pcctx = NULL; struct dfv_file* file_ctx = NULL; int wkr_id = wkr_ctx->wkr_id; spk_stats_t* stats = &wkr_ctx->stats; void* chunk_buf = NULL; size_t chunk_size = slice_def->size * slice_def->num; int dfv_cpu_base = 12+4*wkr_ctx->wkr_id; zlog_notice(sys_zc, "wkr#%d> prepare for recording: ips={0x%x:%d}, dfv={repo={%d:%d}, " "slice={%d, 0x%lx}, cpu_base=%d}", wkr_id, src_id, pc_id, dfv_repo_get_id(slot_def->repo), slot_def->slot_id, slice_def->num, slice_def->size, dfv_cpu_base); // reset stats spk_stats_reset(stats); // open dfv slot file_ctx = dfv_file_open(slot_def->repo, slot_def->slot_id, SPK_DIR_WRITE, slice_def, dfv_cpu_base); if (!file_ctx) { zlog_fatal(sys_zc, "wkr#%d> failed to open dfv file", wkr_id); ret = SPKERR_BADRES; goto out; } // write to dfv #if 0 if (!(sys_env.dbg_flag & SYSDBG_REC_NOTSAVE2DISK)) { size_t warmup_sz = 128*1024*1024; size_t xferred = 0; void * txbuf = NULL; txbuf = memalign(SYS_INTERLACE_SIZE, DFV_CHUNK_SIZE); assert(txbuf); memset(txbuf, 0xfe, DFV_CHUNK_SIZE); while(xferred < warmup_sz) { ssize_t xfer = dfv_file_write(file_ctx, txbuf, DFV_CHUNK_SIZE); if (xfer != DFV_CHUNK_SIZE) { zlog_fatal(sys_zc, "wkr#%d> failed to write to dfv: xfer=%ld, expect=%u", wkr_id, xfer, DFV_CHUNK_SIZE); ret = SPKERR_EACCESS; SAFE_RELEASE(txbuf); goto out; } xferred += xfer; } dfv_file_seek(file_ctx, 0); SAFE_RELEASE(txbuf); } zlog_notice(sys_zc, "wkr#%d> dfv warmup done", wkr_id); #endif // open ips srio pcctx = ips_chan_open(src_id, pc_id); if (!pcctx) { zlog_fatal(sys_zc, "wkr#%d> failed to open ips channel", wkr_id); ret = SPKERR_EACCESS; goto out; } ret = ips_chan_start(pcctx, SPK_DIR_READ); if (ret != SPK_SUCCESS) { zlog_fatal(sys_zc, "wkr#%d> failed to start ips channel", wkr_id); goto out; } zlog_info(sys_zc, "wkr#%d> ips channel started for reading", wkr_id); // start recording uint64_t now = spk_get_tick_count(); uint64_t tm_upstats = now; uint64_t tm_log = now; uint64_t tm_heartbeat = now; ret = SPK_SUCCESS; size_t xfer; zlog_notice(sys_zc, "wkr#%d> ---------- start recording ----------", wkr_id); while(!wkr_ctx->reset_req) { // read from ips for one chunk // FIXME: our link partner must have enough data // before being stopped ssize_t read_size = ips_chan_read(pcctx, &chunk_buf, chunk_size, chunk_size); if (read_size > 0) { // got a chunk from ips assert(read_size == chunk_size); // preserve first buf for snapshot use pthread_mutex_lock(&wkr_ctx->buf_snap_lock); memcpy(wkr_ctx->buf_snap, chunk_buf, SYS_SNAP_BUF_SZ); pthread_mutex_unlock(&wkr_ctx->buf_snap_lock); // write to dfv if (sys_env.dbg_flag & SYSDBG_REC_NOTSAVE2DISK) { xfer = chunk_size; } else { xfer = dfv_file_write(file_ctx, chunk_buf, read_size); } // notify ips to free buffer first ips_chan_free_buf(pcctx, read_size); if (xfer != read_size) { zlog_fatal(sys_zc, "wkr#%d> failed to write to dfv: xfer=%ld, expect=%lu", wkr_id, xfer, read_size); ret = SPKERR_EACCESS; break; } } else if (read_size == 0) { // no data if (sys_ctx.auto_rec) { if (spk_get_tick_count() - tm_heartbeat > SYS_AUTOSTOP_TIMEOUT*1000) { // timeout zlog_warn(sys_zc, "wkr#%d> no data received since last %d secs, stop.", wkr_id, SYS_AUTOSTOP_TIMEOUT); break; } } } else { // failed to got a chunk from ips zlog_fatal(sys_zc, "wkr#%d> failed to read from ips: read_size=%ld", wkr_id, read_size); ret = read_size; break; } tm_heartbeat = now = spk_get_tick_count(); // update local stats spk_stats_inc_xfer(stats, read_size, (read_size / ips_sec_sz)); if (now > tm_upstats) { if (!(sys_env.features & SYSFEA_USE_LOCALSTATS)) { // update channel stats sys_job_update_stats(pcctx, wkr_id); } tm_upstats = now + 1000; } if (now > tm_log) { zlog_notice(sys_zc, " wkr#%d> time=%lu pkts=%lu bytes=%lu ovfl=%lu spd=%.3f MBPS", wkr_id, spk_stats_get_time_elapsed(stats)/1000, spk_stats_get_xfer_pkts(stats), spk_stats_get_xfer_bytes(stats), spk_stats_get_overflow_bytes(stats), BYTE2MB(spk_stats_get_bps_overall(stats))); tm_log = now + 10*1000; } } // // stop recording // // 1. send stop to link partner int stop_ret = ips_chan_stop(pcctx); if (stop_ret != SPK_SUCCESS) { zlog_fatal(sys_zc, "wkr#%d> failed to close ips channel: ret=%d", wkr_id, stop_ret); ret = stop_ret; goto out; } // 2. drain remained data if (ret == SPK_SUCCESS) { // wait for link partner to do padding sleep(1); ssize_t tail_size; do { tail_size = ips_chan_read(pcctx, &chunk_buf, 0, chunk_size); if (tail_size <= 0) { // done break; } zlog_notice(sys_zc, "wkr#%d> got remained data: size=%zd", wkr_id, tail_size); // data must been padded to 64k alignment by link partner assert(!(tail_size & (0x10000-1))); // save remained data to dfv slot if (sys_env.dbg_flag & SYSDBG_REC_NOTSAVE2DISK) { xfer = tail_size; } else { xfer = dfv_file_write(file_ctx, chunk_buf, tail_size); } ips_chan_free_buf(pcctx, tail_size); if (xfer != tail_size) { zlog_fatal(sys_zc, "wkr#%d> failed to write to dfv: xfer=%ld, expect=%lu", wkr_id, xfer, tail_size); ret = SPKERR_EACCESS; goto out; } } while(1); } // 3. update chstat for last time if (!(sys_env.features & SYSFEA_USE_LOCALSTATS)) { sys_job_update_stats(pcctx, wkr_id); } out: zlog_notice(sys_zc, "wkr#%d> ---------- stop recording ---------- ret=%d,", wkr_id, ret); if (stats) { zlog_notice(sys_zc, "wkr#%d> elapsed=%lu, pkts=%lu, bytes=%lu, ovfl=%lu", wkr_id, spk_stats_get_time_elapsed(stats)/1000, stats->xfer.pkts, stats->xfer.bytes, stats->overflow.bytes); } // close dfv slot if (file_ctx) { dfv_file_close(file_ctx); file_ctx = NULL; } // close ips srio if (pcctx) { ips_chan_close(pcctx); pcctx = NULL; } #endif return(ret); }
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; }
void* __sys_wkr_job(void* args) { sys_wkr_ctx_t* wkr_ctx = (sys_wkr_ctx_t*)args; int wkr_id = wkr_ctx->wkr_id; int ips_pipe_id = wkr_id; int ips_pcid = 0; int dfv_pipe_id = wkr_id; sys_ctx_t* ctx = &sys_ctx; sys_env_t* env = &sys_env; ips_epdesc_t* epdesc = &env->ips_desc_tbl[ips_pipe_id]; ips_pcdesc_t* pcdesc = &epdesc->pcdesc_tbl[ips_pcid]; IPS_EPID epid = pcdesc->src_id; dfv_vault_t* vault = ctx->vault; struct dfv_repo* repo = vault->repo_tbl[dfv_pipe_id]; size_t ips_sec_sz = pcdesc->sector_sz; dfv_slice_def_t slice_def; memset(&slice_def, 0, sizeof(dfv_slice_def_t)); slice_def.num = DFV_SLICE_NUM; slice_def.size = DFV_SLICE_SIZE; dfv_slot_def_t slot_def; int cpu = wkr_id + 5; spk_worker_set_affinity(cpu); zlog_notice(sys_zc, "wkr#%d> spawn: cpu=%d", wkr_id, cpu); int ret = -1; while(!wkr_ctx->quit_req) { wkr_ctx->reset_req = 0; ret = -1; sys_jobq_node_t* job_node = sys_jobq_dequeue(&wkr_ctx->job_in); if (!job_node) { // idle usleep(100); continue; } int job_type = job_node->job_type; // got job to do zlog_notice(sys_zc, "wkr#%d> start job: job_type=%s", wkr_id, cmi_desc_cmdtype2str(job_type)); if (job_node->job_type == cmd_type_config) { // config : immediate job ret = __sys_job_do_config(wkr_ctx, epid, ips_pcid, (char*)job_node->cmd_ref->u.all.words, sizeof(job_node->cmd_ref->u.all)); job_node->resp = ret; sys_jobq_enqueue(&wkr_ctx->job_out, job_node); } else if (job_node->job_type == cmd_type_start_rec) { // start_rec: deferred job int slot_id = (int)(intptr_t)job_node->arg; memset(&slot_def, 0, sizeof(dfv_slot_def_t)); slot_def.repo = repo; slot_def.slot_id = slot_id; __JOB_RESPONSE(sys_state_rec, SPK_SUCCESS); spk_stats_reset(&wkr_ctx->stats); ret = __sys_job_do_record(wkr_ctx, epid, ips_pcid, ips_sec_sz, &slot_def, &slice_def); spk_stats_reset(&wkr_ctx->stats); } else if (job_node->job_type == cmd_type_start_play) { // start_play: deferred job uint64_t slot_sz = job_node->arg; int slot_id = job_node->cmd_ref->u.file.index; __JOB_RESPONSE(sys_state_play, SPK_SUCCESS); spk_stats_reset(&wkr_ctx->stats); memset(&slot_def, 0, sizeof(dfv_slot_def_t)); slot_def.repo = repo; slot_def.slot_id = slot_id; ret = __sys_job_do_playback(wkr_ctx, epid, ips_pcid, ips_sec_sz, &slot_def, slot_sz); spk_stats_reset(&wkr_ctx->stats); } else if (job_node->job_type == cmd_type_start_dl) { // start_dl: immediate/deferred job assert(wkr_id == 0); int slot_id = job_node->cmd_ref->u.file.index; uint32_t req_frag = job_node->cmd_ref->u.file.frag_id; uint64_t blk_start = job_node->cmd_ref->u.file.blk_start; uint64_t blk_num = job_node->cmd_ref->u.file.blk_num; if (req_frag == (uint32_t)-1) { // fast mode : deferred __JOB_RESPONSE(sys_state_dl, SPK_SUCCESS); ret = __sys_job_do_download(wkr_ctx, slot_id, req_frag, blk_start, blk_num); } else { // slow mode: immediate ret = sys_func_dl_prepare(slot_id, blk_start, blk_num, req_frag); if (ret == SPK_SUCCESS) { ret = sys_func_dl_sendfrag(slot_id, blk_start, blk_num, req_frag, NULL); } job_node->resp = ret; sys_jobq_enqueue(&wkr_ctx->job_out, job_node); } } else if (job_node->job_type == cmd_type_format) { // format: deferred job assert(wkr_id == 0); __JOB_RESPONSE(sys_state_format, SPK_SUCCESS); ret = dfv_vault_format(sys_ctx.vault); sys_ctx.diskcap = dfv_vault_get_diskcap(sys_ctx.vault); } else { // unknown job assert(0); } zlog_notice(sys_zc, "wkr#%d> job done: job_type=%s, ret=%d", wkr_id, cmi_desc_cmdtype2str(job_type), ret); if (wkr_id == 0 && ret == SPKERR_RESETSYS) { zlog_warn(sys_zc, "wkr#%d> disconnect cmi due to errors", wkr_id); cmi_intf_disconnect(sys_ctx.cmi_intf); } wkr_ctx->wkr_state = sys_state_idle; } zlog_notice(sys_zc, "wkr#%d> terminated", wkr_id); return(NULL); }
/* Zebra client message read function. */ static int zclient_read (struct thread *thread) { size_t already; uint16_t length, command; uint8_t marker, version; struct zclient *zclient; /* Get socket to zebra. */ zclient = THREAD_ARG (thread); zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { if (zclient_debug) zlog_debug ("zclient connection closed socket [%d].", zclient->sock); return zclient_failed(zclient); } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(zclient->ibuf, 0); /* Fetch header values. */ length = stream_getw (zclient->ibuf); marker = stream_getc (zclient->ibuf); version = stream_getc (zclient->ibuf); command = stream_getw (zclient->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zclient->sock, marker, version); return zclient_failed(zclient); } if (length < ZEBRA_HEADER_SIZE) { zlog_err("%s: socket %d message length %u is less than %d ", __func__, zclient->sock, length, ZEBRA_HEADER_SIZE); return zclient_failed(zclient); } /* Length check. */ if (length > STREAM_SIZE(zclient->ibuf)) { struct stream *ns; zlog_warn("%s: message size %u exceeds buffer size %lu, expanding...", __func__, length, (u_long)STREAM_SIZE(zclient->ibuf)); ns = stream_new(length); stream_copy(ns, zclient->ibuf); stream_free (zclient->ibuf); zclient->ibuf = ns; } /* Read rest of zebra packet. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, length-already)) == 0) || (nbyte == -1)) { if (zclient_debug) zlog_debug("zclient connection closed socket [%d].", zclient->sock); return zclient_failed(zclient); } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } } length -= ZEBRA_HEADER_SIZE; if (zclient_debug) zlog_debug("zclient 0x%p command 0x%x \n", (void *)zclient, command); switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) (*zclient->router_id_update) (command, zclient, length); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) (*zclient->interface_add) (command, zclient, length); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) (*zclient->interface_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) (*zclient->interface_address_add) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) (*zclient->interface_address_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) (*zclient->interface_up) (command, zclient, length); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) (*zclient->interface_down) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) (*zclient->ipv4_route_add) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) (*zclient->ipv4_route_delete) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) (*zclient->ipv6_route_add) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) (*zclient->ipv6_route_delete) (command, zclient, length); break; default: break; } if (zclient->sock < 0) /* Connection was closed during packet processing. */ return -1; /* Register read thread. */ stream_reset(zclient->ibuf); zclient_event (ZCLIENT_READ, zclient); return 0; }
/* Kernel routing table and interface updates via routing socket. */ static int kernel_read (struct thread *thread) { int sock; int nbytes; struct rt_msghdr *rtm; /* * This must be big enough for any message the kernel might send. * Rather than determining how many sockaddrs of what size might be * in each particular message, just use RTAX_MAX of sockaddr_storage * for each. Note that the sockaddrs must be after each message * definition, or rather after whichever happens to be the largest, * since the buffer needs to be big enough for a message and the * sockaddrs together. */ union { /* Routing information. */ struct { struct rt_msghdr rtm; struct sockaddr_storage addr[RTAX_MAX]; } r; /* Interface information. */ struct { struct if_msghdr ifm; struct sockaddr_storage addr[RTAX_MAX]; } im; /* Interface address information. */ struct { struct ifa_msghdr ifa; struct sockaddr_storage addr[RTAX_MAX]; } ia; #ifdef RTM_IFANNOUNCE /* Interface arrival/departure */ struct { struct if_announcemsghdr ifan; struct sockaddr_storage addr[RTAX_MAX]; } ian; #endif /* RTM_IFANNOUNCE */ } buf; /* Fetch routing socket. */ sock = THREAD_FD (thread); nbytes= read (sock, &buf, sizeof buf); if (nbytes <= 0) { if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN) zlog_warn ("routing socket error: %s", safe_strerror (errno)); return 0; } thread_add_read (zebrad.master, kernel_read, NULL, sock); if (IS_ZEBRA_DEBUG_KERNEL) rtmsg_debug (&buf.r.rtm); rtm = &buf.r.rtm; /* * Ensure that we didn't drop any data, so that processing routines * can assume they have the whole message. */ if (rtm->rtm_msglen != nbytes) { zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n", rtm->rtm_msglen, nbytes, rtm->rtm_type); return -1; } switch (rtm->rtm_type) { case RTM_ADD: case RTM_DELETE: case RTM_CHANGE: rtm_read (rtm); break; case RTM_IFINFO: ifm_read (&buf.im.ifm); break; case RTM_NEWADDR: case RTM_DELADDR: ifam_read (&buf.ia.ifa); break; #ifdef RTM_IFANNOUNCE case RTM_IFANNOUNCE: ifan_read (&buf.ian.ifan); break; #endif /* RTM_IFANNOUNCE */ default: if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type); break; } return 0; }
/* Wake up configured address if it is not in current kernel address. */ void if_addr_wakeup (struct interface *ifp) { struct listnode *node; struct connected *ifc; struct prefix *p; int ret; for (node = listhead (ifp->connected); node; nextnode (node)) { ifc = getdata (node); p = ifc->address; if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED) && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { /* Address check. */ if (p->family == AF_INET) { if (! if_is_up (ifp)) { if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } ret = if_set_prefix (ifp, ifc); if (ret < 0) { zlog_warn ("Can't set interface's address: %s", strerror(errno)); continue; } SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); zebra_interface_address_add_update (ifp, ifc); if (if_is_up(ifp)) connected_up_ipv4 (ifp, ifc); } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { if (! if_is_up (ifp)) { if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } ret = if_prefix_add_ipv6 (ifp, ifc); if (ret < 0) { zlog_warn ("Can't set interface's address: %s", strerror(errno)); continue; } SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); zebra_interface_address_add_update (ifp, ifc); if (if_is_up(ifp)) connected_up_ipv6 (ifp, ifc); } #endif /* HAVE_IPV6 */ } } }
/* Address read from struct ifa_msghdr. */ static void ifam_read_mesg (struct ifa_msghdr *ifm, union sockunion *addr, union sockunion *mask, union sockunion *brd, char *ifname, short *ifnlen) { caddr_t pnt, end; union sockunion dst; union sockunion gateway; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen; /* Be sure structure is cleared */ memset (mask, 0, sizeof (union sockunion)); memset (addr, 0, sizeof (union sockunion)); memset (brd, 0, sizeof (union sockunion)); memset (&dst, 0, sizeof (union sockunion)); memset (&gateway, 0, sizeof (union sockunion)); /* We fetch each socket variable into sockunion. */ RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt); RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt); RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt); RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen); RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt); RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt); if (IS_ZEBRA_DEBUG_KERNEL) { switch (sockunion_family(addr)) { case AF_INET: { char buf[4][INET_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET,&addr->sin.sin_addr, buf[0],sizeof(buf[0])), ip_masklen(mask->sin.sin_addr), inet_ntop(AF_INET,&brd->sin.sin_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET,&dst.sin.sin_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET,&gateway.sin.sin_addr, buf[3],sizeof(buf[3]))); } break; #ifdef HAVE_IPV6 case AF_INET6: { char buf[4][INET6_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET6,&addr->sin6.sin6_addr, buf[0],sizeof(buf[0])), ip6_masklen(mask->sin6.sin6_addr), inet_ntop(AF_INET6,&brd->sin6.sin6_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET6,&dst.sin6.sin6_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET6,&gateway.sin6.sin6_addr, buf[3],sizeof(buf[3]))); } break; #endif /* HAVE_IPV6 */ default: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs); break; } } /* Assert read up end point matches to end point */ if (pnt != end) zlog_warn ("ifam_read() does't read all socket data"); }
struct isis_circuit * isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) { int old_state; old_state = circuit ? circuit->state : C_STATE_NA; if (isis->debugs & DEBUG_EVENTS) zlog_debug("CSM_EVENT: %s", EVENT2STR(event)); switch (old_state) { case C_STATE_NA: if (circuit) zlog_warn("Non-null circuit while state C_STATE_NA"); assert(circuit == NULL); switch (event) { case ISIS_ENABLE: circuit = isis_circuit_new(); isis_circuit_configure(circuit, (struct isis_area *)arg); circuit->state = C_STATE_CONF; break; case IF_UP_FROM_Z: circuit = isis_circuit_new(); isis_circuit_if_add(circuit, (struct interface *)arg); listnode_add(isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; case ISIS_DISABLE: zlog_warn("circuit already disabled"); break; case IF_DOWN_FROM_Z: zlog_warn("circuit already disconnected"); break; } break; case C_STATE_INIT: assert(circuit); switch (event) { case ISIS_ENABLE: isis_circuit_configure(circuit, (struct isis_area *)arg); if (isis_circuit_up(circuit) != ISIS_OK) { isis_circuit_deconfigure( circuit, (struct isis_area *)arg); break; } circuit->state = C_STATE_UP; isis_event_circuit_state_change(circuit, circuit->area, 1); listnode_delete(isis->init_circ_list, circuit); break; case IF_UP_FROM_Z: assert(circuit); zlog_warn("circuit already connected"); break; case ISIS_DISABLE: zlog_warn("circuit already disabled"); break; case IF_DOWN_FROM_Z: isis_circuit_if_del(circuit, (struct interface *)arg); listnode_delete(isis->init_circ_list, circuit); isis_circuit_del(circuit); circuit = NULL; break; } break; case C_STATE_CONF: assert(circuit); switch (event) { case ISIS_ENABLE: zlog_warn("circuit already enabled"); break; case IF_UP_FROM_Z: isis_circuit_if_add(circuit, (struct interface *)arg); if (isis_circuit_up(circuit) != ISIS_OK) { flog_err( ISIS_ERR_CONFIG, "Could not bring up %s because of invalid config.", circuit->interface->name); flog_err( ISIS_ERR_CONFIG, "Clearing config for %s. Please re-examine it.", circuit->interface->name); if (circuit->ip_router) { circuit->ip_router = 0; circuit->area->ip_circuits--; } if (circuit->ipv6_router) { circuit->ipv6_router = 0; circuit->area->ipv6_circuits--; } circuit_update_nlpids(circuit); isis_circuit_deconfigure(circuit, circuit->area); listnode_add(isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; } circuit->state = C_STATE_UP; isis_event_circuit_state_change(circuit, circuit->area, 1); break; case ISIS_DISABLE: isis_circuit_deconfigure(circuit, (struct isis_area *)arg); isis_circuit_del(circuit); circuit = NULL; break; case IF_DOWN_FROM_Z: zlog_warn("circuit already disconnected"); break; } break; case C_STATE_UP: assert(circuit); switch (event) { case ISIS_ENABLE: zlog_warn("circuit already configured"); break; case IF_UP_FROM_Z: zlog_warn("circuit already connected"); break; case ISIS_DISABLE: isis_circuit_down(circuit); isis_circuit_deconfigure(circuit, (struct isis_area *)arg); circuit->state = C_STATE_INIT; isis_event_circuit_state_change( circuit, (struct isis_area *)arg, 0); listnode_add(isis->init_circ_list, circuit); break; case IF_DOWN_FROM_Z: isis_circuit_down(circuit); isis_circuit_if_del(circuit, (struct interface *)arg); circuit->state = C_STATE_CONF; isis_event_circuit_state_change(circuit, circuit->area, 0); break; } break; default: zlog_warn("Invalid circuit state %d", old_state); } if (isis->debugs & DEBUG_EVENTS) zlog_debug("CSM_STATE_CHANGE: %s -> %s ", STATE2STR(old_state), circuit ? STATE2STR(circuit->state) : STATE2STR(C_STATE_NA)); return circuit; }
/* 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; }
/* Flush enough data to fill a terminal window of the given scene (used only by vty telnet interface). */ buffer_status_t buffer_flush_window (struct buffer *b, int fd, int width, int height, int erase_flag, int no_more_flag) { int nbytes; int iov_alloc; int iov_index; struct iovec *iov; struct iovec small_iov[3]; char more[] = " --More-- "; char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; struct buffer_data *data; int column; if (!b->head) return BUFFER_EMPTY; if (height < 1) { zlog_warn("%s called with non-positive window height %d, forcing to 1", __func__, height); height = 1; } else if (height >= 2) height--; if (width < 1) { zlog_warn("%s called with non-positive window width %d, forcing to 1", __func__, width); width = 1; } /* For erase and more data add two to b's buffer_data count.*/ if (b->head->next == NULL) { iov_alloc = sizeof(small_iov)/sizeof(small_iov[0]); iov = small_iov; } else { iov_alloc = ((height*(width+2))/b->size)+10; iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov)); } iov_index = 0; /* Previously print out is performed. */ if (erase_flag) { iov[iov_index].iov_base = erase; iov[iov_index].iov_len = sizeof erase; iov_index++; } /* Output data. */ column = 1; /* Column position of next character displayed. */ for (data = b->head; data && (height > 0); data = data->next) { size_t cp; cp = data->sp; while ((cp < data->cp) && (height > 0)) { /* Calculate lines remaining and column position after displaying this character. */ if (data->data[cp] == '\r') column = 1; else if ((data->data[cp] == '\n') || (column == width)) { column = 1; height--; } else column++; cp++; } iov[iov_index].iov_base = (char *)(data->data + data->sp); iov[iov_index++].iov_len = cp-data->sp; data->sp = cp; if (iov_index == iov_alloc) /* This should not ordinarily happen. */ { iov_alloc *= 2; if (iov != small_iov) { zlog_warn("%s: growing iov array to %d; " "width %d, height %d, size %lu", __func__, iov_alloc, width, height, (u_long)b->size); iov = XREALLOC(MTYPE_TMP, iov, iov_alloc*sizeof(*iov)); } else { /* This should absolutely never occur. */ zlog_err("%s: corruption detected: iov_small overflowed; " "head %p, tail %p, head->next %p", __func__, b->head, b->tail, b->head->next); iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov)); memcpy(iov, small_iov, sizeof(small_iov)); } } } /* In case of `more' display need. */ if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) { iov[iov_index].iov_base = more; iov[iov_index].iov_len = sizeof more; iov_index++; } #ifdef IOV_MAX /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g. example: Solaris2.6 are defined IOV_MAX size at 16. */ { struct iovec *c_iov = iov; nbytes = 0; /* Make sure it's initialized. */ while (iov_index > 0) { int iov_size; iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index); if ((nbytes = writev(fd, c_iov, iov_size)) < 0) { zlog_warn("%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); break; } /* move pointer io-vector */ c_iov += iov_size; iov_index -= iov_size; } } #else /* IOV_MAX */ if ((nbytes = writev (fd, iov, iov_index)) < 0) zlog_warn("%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); #endif /* IOV_MAX */ /* Free printed buffer data. */ while (b->head && (b->head->sp == b->head->cp)) { struct buffer_data *del; if (!(b->head = (del = b->head)->next)) b->tail = NULL; BUFFER_DATA_FREE(del); } if (iov != small_iov) XFREE (MTYPE_TMP, iov); return (nbytes < 0) ? BUFFER_ERROR : (b->head ? BUFFER_PENDING : BUFFER_EMPTY); }
int isis_recv_pdu_bcast(struct isis_circuit *circuit, uint8_t *ssnpa) { struct pollfd fds[1]; struct strbuf ctlbuf, databuf; int flags, retv; dl_unitdata_ind_t *dui = (dl_unitdata_ind_t *)dlpi_ctl; memset(fds, 0, sizeof(fds)); fds[0].fd = circuit->fd; fds[0].events = POLLIN | POLLPRI; if (poll(fds, 1, 0) <= 0) return ISIS_WARNING; memset(&ctlbuf, 0, sizeof(ctlbuf)); memset(&databuf, 0, sizeof(databuf)); ctlbuf.maxlen = sizeof(dlpi_ctl); ctlbuf.buf = (void *)dlpi_ctl; databuf.maxlen = sizeof(sock_buff); databuf.buf = (void *)sock_buff; flags = 0; retv = getmsg(circuit->fd, &ctlbuf, &databuf, &flags); if (retv < 0) { zlog_warn("isis_recv_pdu_bcast: getmsg failed: %s", safe_strerror(errno)); return ISIS_WARNING; } if (retv & (MORECTL | MOREDATA)) { while (retv & (MORECTL | MOREDATA)) { flags = 0; retv = getmsg(circuit->fd, &ctlbuf, &databuf, &flags); } return ISIS_WARNING; } if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE || dui->dl_primitive != DL_UNITDATA_IND) return ISIS_WARNING; if (dui->dl_src_addr_length != ETHERADDRL + 2 || dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE || dui->dl_src_addr_offset + dui->dl_src_addr_length > (size_t)ctlbuf.len) return ISIS_WARNING; memcpy(ssnpa, (char *)dui + dui->dl_src_addr_offset + (circuit->sap_length > 0 ? circuit->sap_length : 0), ETHERADDRL); if (databuf.len < LLC_LEN || sock_buff[0] != ISO_SAP || sock_buff[1] != ISO_SAP || sock_buff[2] != 3) return ISIS_WARNING; stream_write(circuit->rcv_stream, sock_buff + LLC_LEN, databuf.len - LLC_LEN); stream_set_getp(circuit->rcv_stream, 0); return ISIS_OK; }
/* Routing information change from the kernel. */ int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct rtmsg *rtm; struct rtattr *tb [RTA_MAX + 1]; char anyaddr[16] = {0}; int index; int table; void *dest; void *gate; rtm = NLMSG_DATA (h); if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { /* If this is not route add/delete message print warning. */ zlog_warn ("Kernel message: %d\n", h->nlmsg_type); return 0; } /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("%s %s %s proto %s", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", lookup (rtproto_str, rtm->rtm_protocol)); if (rtm->rtm_type != RTN_UNICAST) { return 0; } table = rtm->rtm_table; if (table != RT_TABLE_MAIN && table != rtm_table_default) { return 0; } len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); if (rtm->rtm_flags & RTM_F_CLONED) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; if (rtm->rtm_protocol == RTPROT_KERNEL) return 0; if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE) return 0; if (rtm->rtm_src_len != 0) { zlog_warn ("netlink_route_change(): no src len"); return 0; } index = 0; dest = NULL; gate = NULL; if (tb[RTA_OIF]) index = *(int *) RTA_DATA (tb[RTA_OIF]); if (tb[RTA_DST]) dest = RTA_DATA (tb[RTA_DST]); else dest = anyaddr; if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_info ("RTM_NEWROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); else zlog_info ("RTM_DELROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; char buf[BUFSIZ]; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_info ("RTM_NEWROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); else zlog_info ("RTM_DELROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); } #endif /* HAVE_IPV6 */ return 0; }