int sockopt_tcp_signature (int sock, union sockunion *su, const char *password) { #define CONFIG_TCP_MD5SIG 1 #define TCP_MD5SIG 14 #define GNU_LINUX 1 #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX) /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's * version of the Quagga patch (based on work by Rick Payne, and Bruce * Simpson) */ #define TCP_MD5_AUTH 13 #define TCP_MD5_AUTH_ADD 1 #define TCP_MD5_AUTH_DEL 2 struct tcp_rfc2385_cmd { u_int8_t command; /* Command - Add/Delete */ u_int32_t address; /* IPV4 address associated */ u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */ void *key; /* MD5 Key */ } cmd; struct in_addr *addr = &su->sin.sin_addr; cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL); cmd.address = addr->s_addr; cmd.keylen = (password != NULL ? strlen (password) : 0); cmd.key = password; return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); #elif CONFIG_TCP_MD5SIG int ret; #ifndef GNU_LINUX /* * XXX Need to do PF_KEY operation here to add/remove an SA entry, * and add/remove an SP entry for this peer's packet flows also. */ int md5sig = password && *password ? 1 : 0; #else struct { struct { unsigned short ss_family; char __data[128 - sizeof(unsigned short)]; } tcpm_addr; /* address associated */ __u16 __tcpm_pad1; /* zero */ __u16 tcpm_keylen; /* key length */ __u32 __tcpm_pad2; /* zero */ __u8 tcpm_key[80]; /* key (binary) */ } md5sig; //struct tcp_md5sig md5sig; int keylen = 0; union sockunion *su2, *susock; if(NULL != password) keylen = strlen(password) ; /* Figure out whether the socket and the sockunion are the same family.. * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think.. */ susock = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); if(NULL == susock) { return -1; } if (!( sockunion_getsockname (sock, susock))) return -1; if (susock->sa.sa_family == su->sa.sa_family) su2 = su; else { /* oops.. */ su2 = susock; if (su2->sa.sa_family == AF_INET) { sockunion_free (susock); return 0; } #ifdef HAVE_IPV6 /* If this does not work, then all users of this sockopt will need to * differentiate between IPv4 and IPv6, and keep seperate sockets for * each. * * Sadly, it doesn't seem to work at present. It's unknown whether * this is a bug or not. */ if (su2->sa.sa_family == AF_INET6 && su->sa.sa_family == AF_INET) { su2->sin6.sin6_family = AF_INET6; /* V4Map the address */ memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr)); su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4); } #endif } memset (&md5sig, 0, sizeof (md5sig)); memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2)); md5sig.tcpm_keylen = keylen; if (keylen) memcpy (md5sig.tcpm_key, password, keylen); sockunion_free (susock); #endif /* GNU_LINUX */ if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0) { /* ENOENT is harmless. It is returned when we clear a password for which one was not previously set. */ if (ENOENT == errno) ret = 0; else zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s", sock, safe_strerror(errno)); } return ret; #else /* HAVE_TCP_MD5SIG */ return -2; #endif /* !HAVE_TCP_MD5SIG */ }
void pim_init() { srandom(time(NULL)); if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, PIM_ALL_PIM_ROUTERS, errno, safe_strerror(errno)); zassert(0); return; } qpim_channel_oil_list = list_new(); if (!qpim_channel_oil_list) { zlog_err("%s %s: failure: channel_oil_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return; } qpim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free; qpim_upstream_list = list_new(); if (!qpim_upstream_list) { zlog_err("%s %s: failure: upstream_list=list_new()", __FILE__, __PRETTY_FUNCTION__); pim_free(); return; } qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free; qpim_static_route_list = list_new(); if (!qpim_static_route_list) { zlog_err("%s %s: failure: static_route_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return; } qpim_static_route_list->del = (void (*)(void *)) pim_static_route_free; qpim_mroute_socket_fd = -1; /* mark mroute as disabled */ qpim_mroute_oif_highest_vif_index = -1; zassert(!qpim_debugs); zassert(!PIM_MROUTE_IS_ENABLED); qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY; /* RFC 4601: 4.6.3. Assert Metrics assert_metric infinite_assert_metric() { return {1,infinity,infinity,0} } */ qpim_infinite_assert_metric.rpt_bit_flag = 1; qpim_infinite_assert_metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; qpim_infinite_assert_metric.ip_address = qpim_inaddr_any; pim_cmd_init(); pim_ssmpingd_init(); }
/* generator of layered networks for the shortest paths problem; extended DIMACS format for output */ int gen_spgrid_topology (struct vty *vty, struct list *topology) { /* ----- ajusting parameters ----- */ /* spanning */ if ( cl < cm ) { lx = cl; cl = cm; cm = lx; } /* additional arcs */ if ( al < am ) { lx = al; al = am; am = lx; } /* interlayered arcs */ if ( il < im ) { lx = il; il = im; im = lx; } /* potential parameters */ if ( p_f ) { if ( ! pl_f ) pl = il; if ( ! pm_f ) pm = im; if ( pl < pm ) { lx = pl; pl = pm; pm = lx; } } /* number of nodes and arcs */ n = (double)X *(double)Y + 1; m = (double)Y; /* arcs from source */ switch ( cw ) { case PATH: mc = (double)Y - 1; break; case CYCLE: mc = (double)Y; break; case DOUBLE_CYCLE: mc = 2*(double)Y; } m += (double)X * (double)mc; /* spanning arcs */ m += (double)X * (double)ax; /* additional arcs */ /* interlayered arcs */ for ( x = 0; x < X; x ++ ) { dl = ( ( X - x - 1 ) + ( ih - 1 ) ) / ih; if ( dl > ix ) dl = ix; m += (double)Y * (double)dl; } /* artifical source parameters */ if ( s_f ) { m += n; n ++ ; if ( ! sm_f ) sm = sl; if ( sl < sm ) { lx = sl; sl = sm; sm = lx; } } if ( n >= (double)LONG_MAX || m >= (double)LONG_MAX ) { zlog_err ("Too large problem. It can't be generated\n"); exit (4); } else { n0 = (long)n; m0 = (long)m; } if ( ip_f ) mess = (long*) calloc ( Y, sizeof ( long ) ); /* printing title */ zlog_info ("Generating topology for ISIS"); source = ( s_f ) ? n0-1 : n0; if ( p_f ) /* generating potentials */ { p = (long*) calloc ( n0+1, sizeof (long) ); seed1 = 2*seed + 1; init_rand ( seed1); pl = pl - pm + 1; for ( x = 0; x < X; x ++ ) for ( y = 0; y < Y; y ++ ) { p_t = pm + nrand ( pl ); if ( pn_f ) p_t *= (long) ( (1 + x) * pn ); if ( ps_f ) p_t *= (long) ( (1 + x) * ( (1 + x) * ps )); p[ NODE ( x, y ) ] = p_t; } p[n0] = 0; if ( s_f ) p[n0-1] = 0; } if ( s_f ) /* additional arcs from artifical source */ { seed2 = 3*seed + 1; init_rand ( seed2 ); sl = sl - sm + 1; for ( x = X - 1; x >= 0; x -- ) for ( y = Y - 1; y >= 0; y -- ) { i = NODE ( x, y ); s = sm + nrand ( sl ); print_arc (vty, topology, n0, i, s ); } print_arc (vty, topology, n0, n0-1, 0 ); } /* ----- generating arcs within layers ----- */ init_rand ( seed ); cl = cl - cm + 1; al = al - am + 1; for ( x = 0; x < X; x ++ ) { /* generating arcs within one layer */ for ( y = 0; y < Y-1; y ++ ) { /* generating spanning graph */ i = NODE ( x, y ); j = NODE ( x, y+1 ); l = cm + nrand ( cl ); print_arc (vty, topology, i, j, l ); if ( cw == DOUBLE_CYCLE ) { l = cm + nrand ( cl ); print_arc (vty, topology, j, i, l ); } } if ( cw <= CYCLE ) { i = NODE ( x, Y-1 ); j = NODE ( x, 0 ); l = cm + nrand ( cl ); print_arc (vty, topology, i, j, l ); if ( cw == DOUBLE_CYCLE ) { l = cm + nrand ( cl ); print_arc (vty, topology, j, i, l ); } } /* generating additional arcs */ for ( k = ax; k > 0; k -- ) { yy1 = nrand ( Y ); do yy2 = nrand ( Y ); while ( yy2 == yy1 ); i = NODE ( x, yy1 ); j = NODE ( x, yy2 ); l = am + nrand ( al ); print_arc (vty, topology, i, j, l ); } } /* ----- generating interlayered arcs ------ */ il = il - im + 1; /* arcs from the source */ for ( y = 0; y < Y; y ++ ) { l = im + nrand ( il ); i = NODE ( 0, y ); print_arc (vty, topology, source, i, l ); } for ( x = 0; x < X-1; x ++ ) { /* generating arcs from one layer */ for ( count = 0, xn = x + 1; count < ix && xn < X; count ++, xn += ih ) { if ( ip_f ) for ( y = 0; y < Y; y ++ ) mess[y] = y; for ( y = 0; y < Y; y ++ ) { i = NODE ( x, y ); dx = xn - x; if ( ip_f ) { yyp = nrand(Y-y); yyn = mess[ yyp ]; mess[ yyp ] = mess[ Y - y - 1 ]; } else yyn = y; j = NODE ( xn, yyn ); l = im + nrand ( il ); if ( in != 0 ) l *= (long) ( in * dx ); if ( is_f ) l *= (long) ( ( is * dx ) * dx ); print_arc (vty, topology, i, j, l ); } } } /* all is done */ return ext; return 0; }
/* 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 }
/* * 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; }
/* Main startup routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = ZEBRA_VTY_PORT; int dryrun = 0; int batch_mode = 0; int daemon_mode = 0; char *config_file = NULL; char *progname; struct thread thread; char *zserv_path = NULL; /* Set umask before anything for security */ umask (0027); /* preserve my name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ZEBRA, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); while (1) { int opt; #ifdef HAVE_NETLINK opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vs:C", longopts, 0); #else opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vC", longopts, 0); #endif /* HAVE_NETLINK */ if (opt == EOF) break; switch (opt) { case 0: break; case 'b': batch_mode = 1; case 'd': daemon_mode = 1; break; case 'k': keep_kernel_mode = 1; break; case 'C': dryrun = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zserv_path = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and zebra not listening on zebra port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = ZEBRA_VTY_PORT; break; case 'r': retain_mode = 1; break; #ifdef HAVE_NETLINK case 's': nl_rcvbufsize = atoi (optarg); break; #endif /* HAVE_NETLINK */ case 'u': zserv_privs.user = optarg; break; case 'g': zserv_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Make master thread emulator. */ zebrad.master = thread_master_create (); /* privs initialise */ zprivs_init (&zserv_privs); /* Vty related initialize. */ signal_init (zebrad.master, Q_SIGC(zebra_signals), zebra_signals); cmd_init (1); vty_init (zebrad.master); memory_init (); /* Zebra related initialize. */ zebra_init (); rib_init (); zebra_if_init (); zebra_debug_init (); router_id_init(); zebra_vty_init (); access_list_init (); prefix_list_init (); rtadv_init (); #ifdef HAVE_IRDP irdp_init(); #endif /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ /* Make kernel routing socket. */ kernel_init (); interface_list (); route_read (); /* Sort VTY commands. */ sort_node (); #ifdef HAVE_SNMP zebra_snmp_init (); #endif /* HAVE_SNMP */ /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in * zebra->ribq structure until we enter the main execution loop. * The notifications from kernel will show originating PID equal * to that after daemon() completes (if ever called). */ vty_read_config (config_file, config_default); /* Don't start execution if we are in dry-run mode */ if (dryrun) return(0); /* Clean up rib. */ rib_weed_tables (); /* Exit when zebra is working in batch mode. */ if (batch_mode) exit (0); /* Daemonize. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("Zebra daemon failed: %s", strerror(errno)); exit (1); } /* Output pid of zebra. */ pid_output (pid_file); /* After we have successfully acquired the pidfile, we can be sure * about being the only copy of zebra process, which is submitting * changes to the FIB. * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, * we have to have route_read() called before. */ if (! keep_kernel_mode) rib_sweep_route (); /* Needed for BSD routing socket. */ pid = getpid (); /* This must be done only after locking pidfile (bug #403). */ zebra_zserv_socket_init (zserv_path); /* Make vty server socket. */ vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); while (thread_fetch (zebrad.master, &thread)) thread_call (&thread); /* Not reached... */ return 0; }
static struct bgp_nexthop_cache * zlookup_read_ipv6 (void) { struct stream *s; uint16_t length; u_char version, marker; struct in6_addr raddr; uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); /* XXX: ignoring nbytes, see also zread_lookup */ stream_read (s, zlookup->sock, 2); length = stream_getw (s); stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } /* XXX: ignoring command */ stream_getw (s); /* XXX: not actually doing anything with raddr */ stream_get (&raddr, s, 16); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop->gate.ipv6, s, 16); break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: stream_get (&nexthop->gate.ipv6, s, 16); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; }
/* Handle an interface delete event */ void if_delete_update (struct interface *ifp) { struct connected *ifc; struct prefix *p; struct route_node *rn; struct zebra_if *zebra_if; zebra_if = ifp->info; if (if_is_up(ifp)) { zlog_err ("interface %s index %d is still up while being deleted.", ifp->name, ifp->ifindex); return; } /* Mark interface as inactive */ UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s index %d is now inactive.", ifp->name, ifp->ifindex); /* Delete connected routes from the kernel. */ if (ifp->connected) { struct listnode *node; struct listnode *last = NULL; while ((node = (last ? last->next : listhead (ifp->connected)))) { ifc = listgetdata (node); p = ifc->address; if (p->family == AF_INET && (rn = route_node_lookup (zebra_if->ipv4_subnets, p))) { struct listnode *anode; struct listnode *next; struct listnode *first; struct list *addr_list; route_unlock_node (rn); addr_list = (struct list *) rn->info; /* Remove addresses, secondaries first. */ first = listhead (addr_list); for (anode = first->next; anode || first; anode = next) { if (!anode) { anode = first; first = NULL; } next = anode->next; ifc = listgetdata (anode); p = ifc->address; connected_down_ipv4 (ifp, ifc); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* Remove from subnet chain. */ list_delete_node (addr_list, anode); route_unlock_node (rn); /* Remove from interface address list (unconditionally). */ if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { listnode_delete (ifp->connected, ifc); connected_free (ifc); } else last = node; } /* Free chain list and respective route node. */ list_delete (addr_list); rn->info = NULL; route_unlock_node (rn); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { connected_down_ipv6 (ifp, ifc); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) last = node; else { listnode_delete (ifp->connected, ifc); connected_free (ifc); } } #endif /* HAVE_IPV6 */ else { last = node; } } } zebra_interface_delete_update (ifp); /* Update ifindex after distributing the delete message. This is in case any client needs to have the old value of ifindex available while processing the deletion. Each client daemon is responsible for setting ifindex to IFINDEX_INTERNAL after processing the interface deletion message. */ ifp->ifindex = IFINDEX_INTERNAL; }
int bgp_socket (struct bgp *bgp, unsigned short port) { int ret; struct addrinfo req; struct addrinfo *ainfo; struct addrinfo *ainfo_save; int sock = 0; char port_str[BUFSIZ]; memset (&req, 0, sizeof (struct addrinfo)); req.ai_flags = AI_PASSIVE; req.ai_family = AF_UNSPEC; req.ai_socktype = SOCK_STREAM; sprintf (port_str, "%d", port); port_str[sizeof (port_str) - 1] = '\0'; ret = getaddrinfo (NULL, port_str, &req, &ainfo); if (ret != 0) { zlog_err ("getaddrinfo: %s", gai_strerror (ret)); return -1; } ainfo_save = ainfo; do { if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) continue; sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); if (sock < 0) { zlog_err ("socket: %s", strerror (errno)); continue; } sockopt_reuseaddr (sock); sockopt_reuseport (sock); ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); if (ret < 0) { zlog_err ("bind: %s", strerror (errno)); close (sock); continue; } ret = listen (sock, 3); if (ret < 0) { zlog_err ("listen: %s", strerror (errno)); close (sock); continue; } #ifdef HAVE_TCP_SIGNATURE #ifdef HAVE_LINUX_TCP_SIGNATURE bm->sock = sock; #endif /* HAVE_LINUX_TCP_SIGNATURE */ #ifdef HAVE_OPENBSD_TCP_SIGNATURE bgp_tcpsig_set (sock, 0); bm->sock = -1; #endif /* HAVE_OPENBSD_TCP_SIGNATURE */ #endif /* HAVE_TCP_SIGNATURE */ thread_add_read (master, bgp_accept, bgp, sock); } while ((ainfo = ainfo->ai_next) != NULL); freeaddrinfo (ainfo_save); return sock; }
static void parse_irdp_packet(char *p, int len, struct interface *ifp) { struct ip *ip = (struct ip *)p ; struct icmphdr *icmp; struct in_addr src; int ip_hlen, iplen, datalen; struct zebra_if *zi; struct irdp_interface *irdp; zi = ifp->info; if (!zi) return; irdp = &zi->irdp; if (!irdp) return; ip_hlen = ip->ip_hl << 2; sockopt_iphdrincl_swab_systoh (ip); iplen = ip->ip_len; datalen = len - ip_hlen; src = ip->ip_src; if (len != iplen) { zlog_err ("IRDP: RX length doesnt match IP length"); return; } if (iplen < ICMP_MINLEN) { zlog_err ("IRDP: RX ICMP packet too short from %s\n", inet_ntoa (src)); return; } /* XXX: RAW doesnt receive link-layer, surely? ??? */ /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen + len of IP-header) 14+20 */ if (iplen > IRDP_RX_BUF-34) { zlog_err ("IRDP: RX ICMP packet too long from %s\n", inet_ntoa (src)); return; } icmp = (struct icmphdr *) (p+ip_hlen); /* check icmp checksum */ if (in_cksum (icmp, datalen) != icmp->checksum) { zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", inet_ntoa (src)); return; } /* Handle just only IRDP */ if (!(icmp->type == ICMP_ROUTERADVERT || icmp->type == ICMP_ROUTERSOLICIT)) return; if (icmp->code != 0) { zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code," " silently ignored", icmp->type, inet_ntoa (src)); return; } if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST) && (irdp->flags & IF_BROADCAST)) || (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP && !(irdp->flags & IF_BROADCAST))) { zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n", inet_ntoa (src), ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ? "multicast" : inet_ntoa (ip->ip_dst), ifp->name, irdp->flags & IF_BROADCAST ? "broadcast" : "multicast"); zlog_warn ("IRDP: Please correct settings\n"); return; } switch (icmp->type) { case ICMP_ROUTERADVERT: break; case ICMP_ROUTERSOLICIT: if(irdp->flags & IF_DEBUG_MESSAGES) zlog_debug ("IRDP: RX Solicit on %s from %s\n", ifp->name, inet_ntoa (src)); process_solicit(ifp); break; default: zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored", icmp->type, inet_ntoa (src)); } }
s32 bgp_nlri_parse_6vpe (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; struct prefix_rd prd; int psize; int prefixlen; u_int32_t label; u_char *tagpnt; /* Check peer status. */ if (peer->status != Established) return 0; pnt = packet->nlri; lim = pnt + packet->length; for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ prefixlen = *pnt++; p.family = AF_INET6; psize = PSIZE (prefixlen); if (prefixlen < 88) { zlog_err ("prefix length is less than 88: %d", prefixlen); return -1; } p.prefixlen = prefixlen - 88; label = decode_label (pnt); /* Copyr label to prefix. */ tagpnt = pnt; prd.family = AF_UNSPEC; prd.prefixlen = 64; memcpy (prd.val, pnt + 3 ,8); memcpy (&p.u.prefix6, pnt + 11 , psize - 11); if (pnt + psize > lim) return -1; if (attr) bgp_update (peer, &p, attr, AFI_IP6, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); else bgp_withdraw (peer, &p, attr, AFI_IP6, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; }
/* Main startup routine. */ int rtm_init (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = ZEBRA_VTY_PORT; int dryrun = 0; int batch_mode = 0; int daemon_mode = 0; char *config_file = NULL; char *progname; struct thread thread; char *zserv_path = NULL; /* Set umask before anything for security */ umask (0027); /* preserve my name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ZEBRA, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* Make master thread emulator. */ zebrad.master = thread_master_create (); /* privs initialise */ zprivs_init (&zserv_privs); /* Vty related initialize. */ signal_init (zebrad.master, Q_SIGC(zebra_signals), zebra_signals); #if 0 /* * All CLI command registrations commented out */ cmd_init (1); vty_init (zebrad.master); memory_init (); zebra_init (); zebra_if_init (); zebra_vty_init (); /* Sort VTY commands. */ sort_node (); #endif /* Zebra related initialize. */ rib_init (); zebra_debug_init (); router_id_init(); access_list_init (); prefix_list_init (); rtadv_init (); #ifdef HAVE_IRDP irdp_init(); #endif /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ #if 0 /* * The Kernel FIB Interface is no longer needed */ /* Make kernel routing socket. */ kernel_init (); interface_list (); route_read (); #endif #ifdef HAVE_SNMP zebra_snmp_init (); #endif /* HAVE_SNMP */ /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in * zebra->ribq structure until we enter the main execution loop. * The notifications from kernel will show originating PID equal * to that after daemon() completes (if ever called). */ vty_read_config (config_file, config_default); /* Don't start execution if we are in dry-run mode */ if (dryrun) return(0); /* Clean up rib. */ rib_weed_tables (); /* Exit when zebra is working in batch mode. */ if (batch_mode) exit (0); #if 0 /* Daemonize. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("Zebra daemon failed: %s", strerror(errno)); exit (1); } /* Output pid of zebra. */ pid_output (pid_file); #endif /* After we have successfully acquired the pidfile, we can be sure * about being the only copy of zebra process, which is submitting * changes to the FIB. * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, * we have to have route_read() called before. */ if (! keep_kernel_mode) rib_sweep_route (); #if 0 /* Needed for BSD routing socket. */ pid = getpid (); /* This must be done only after locking pidfile (bug #403). */ zebra_zserv_socket_init (zserv_path); /* Make vty server socket. */ vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); #endif /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); while (thread_fetch (zebrad.master, &thread)) thread_call (&thread); /* Not reached... */ return 0; }
int ospf_sock_init (int packet_flag) { int ospf_sock; int ret, hincl = 1; int ospf_hello = OSPF_IP_HELLO_PACKET; int ospf_other = OSPF_IP_OTHER_PACKET; ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf_sock < 0) { int save_errno = errno; zlog_err ("ospf_read_sock_init: socket: %s", safe_strerror (save_errno)); exit(1); } #ifdef IP_HDRINCL /* we will include IP header with packet */ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); if (ret < 0) { int save_errno = errno; zlog_warn ("Can't set IP_HDRINCL option for fd %d: %s", ospf_sock, safe_strerror(save_errno)); } #elif defined (IPTOS_PREC_INTERNETCONTROL) #warning "IP_HDRINCL not available on this system" #warning "using IPTOS_PREC_INTERNETCONTROL" ret = setsockopt_ipv4_tos(ospf_sock, IPTOS_PREC_INTERNETCONTROL); if (ret < 0) { int save_errno = errno; zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s", tos, ospf_sock, safe_strerror(save_errno)); close (ospf_sock); /* Prevent sd leak. */ return ret; } #else /* !IPTOS_PREC_INTERNETCONTROL */ #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL" zlog_warn ("IP_HDRINCL option not available"); #endif /* IP_HDRINCL */ ret = setsockopt_ifindex (AF_INET, ospf_sock, 1); if (ret < 0) { zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock); } ret = setsockopt_so_recvbuf (ospf_sock, OSPF_PACKET_RECV_BUFFLEN); if (ret < 0) { zlog_warn ("Can't set SO_RCVBUF %d to socket %d", OSPF_PACKET_RECV_BUFFLEN, ospf_sock); } if(packet_flag == OSPF_IP_HELLO_PACKET) { set_nonblocking(ospf_sock); setsockopt (ospf_sock, SOL_SOCKET, SO_SET_OSPF_FILTER, &ospf_hello, sizeof (ospf_hello)); } if(packet_flag == OSPF_IP_OTHER_PACKET) { set_nonblocking(ospf_sock); setsockopt (ospf_sock, SOL_SOCKET, SO_SET_OSPF_FILTER, &ospf_other, sizeof (ospf_hello)); } return ospf_sock; }
/* Take a sequence of payload (routing) RTE structures, decide on particular * authentication required for the given interface and build a complete RIP * packet in a stream structure. The packet will consist of header, optional * heading RTE, the payload RTEs and optional trailing data. Return the stream. */ int rip_auth_make_packet ( struct rip_interface * ri, struct stream * packet, struct stream * rtes, const u_int8_t version, const u_int8_t command ) { struct key *key = NULL; char *auth_str = NULL; if (IS_RIP_DEBUG_AUTH) zlog_debug ("interface auth type is '%s', inet RTEs payload size is %zuB", LOOKUP (rip_ffff_type_str, ri->auth_type), stream_get_endp (rtes)); /* packet header, unconditional */ stream_reset (packet); stream_putc (packet, command); stream_putc (packet, version); stream_putw (packet, 0); /* authentication leading RTE, conditional */ if (version == RIPv2 && ri->auth_type != RIP_NO_AUTH) { if (ri->key_chain) { struct keychain *keychain; keychain = keychain_lookup (ri->key_chain); if (keychain) { if (IS_RIP_DEBUG_AUTH) zlog_debug ("trying configured key chain '%s'", ri->key_chain); key = key_lookup_for_send (keychain); } else { if (IS_RIP_DEBUG_AUTH) zlog_debug ("key chain '%s' is configured, but does not exist", ri->key_chain); } } /* Pick correct auth string for sends, prepare auth_str buffer for use. * (left justified and padded). * * presumes one of ri or key is valid, and that the auth strings they point * to are nul terminated. If neither are present, auth_str will be fully * zero padded. * */ if (key && key->string) { if (IS_RIP_DEBUG_AUTH) zlog_debug ("using keychain '%s', key %u for sending", ri->key_chain, key->index); auth_str = key->string; } else if (ri->auth_str) { if (IS_RIP_DEBUG_AUTH) zlog_debug ("using interface authentication string"); auth_str = ri->auth_str; } if (auth_str == NULL) { if (IS_RIP_DEBUG_AUTH) zlog_debug ("authentication string lookup failed"); return -1; } rip_auth_write_leading_rte (packet, ri, key ? key->index % 256 : 1, auth_str, RIP_HEADER_SIZE + RIP_RTE_SIZE + stream_get_endp (rtes)); } /* RTEs payload, unconditional */ if (stream_get_endp (rtes) % RIP_RTE_SIZE) { zlog_err ("%s: malformed input RTE buffer", __func__); return -1; } stream_write (packet, STREAM_DATA (rtes), stream_get_endp (rtes)); stream_reset (rtes); /* authentication trailing data, even more conditional */ if (version == RIPv2 && ri->auth_type == RIP_AUTH_HASH) rip_auth_write_trailer (packet, ri, auth_str); return 0; }
static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; char src_str[100]; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); if (!neigh) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*neigh)); return 0; } neigh->creation = pim_time_monotonic_sec(); neigh->source_addr = source_addr; neigh->hello_options = hello_options; neigh->propagation_delay_msec = propagation_delay; neigh->override_interval_msec = override_interval; neigh->dr_priority = dr_priority; neigh->generation_id = generation_id; neigh->prefix_list = addr_list; neigh->t_expire_timer = 0; neigh->interface = ifp; pim_neighbor_timer_reset(neigh, holdtime); pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str)); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s: creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, ifp->name); if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec; } if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) { pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { /* update num. of neighbors without hello option lan_delay */ ++pim_ifp->pim_number_of_nonlandelay_neighbors; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)) { /* update num. of neighbors without hello option dr_pri */ ++pim_ifp->pim_dr_num_nondrpri_neighbors; } return neigh; }
/* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct peer *peer; struct peer *peer1; struct bgp *bgp; char buf[SU_ADDRSTRLEN]; /* Regiser accept thread. */ accept_sock = THREAD_FD (thread); bgp = THREAD_ARG (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } thread_add_read (master, bgp_accept, bgp, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno)); return -1; } if (BGP_DEBUG (events, EVENTS)) zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); /* Check remote IP address */ peer1 = peer_lookup (bgp, &su); if (! peer1 || peer1->status == Idle) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) zlog_info ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else zlog_info ("[Event] BGP connection IP address %s is Idle state", inet_sutop (&su, buf)); } close (bgp_sock); return -1; } /* In case of peer is EBGP, we should set TTL for this connection. */ if (peer_sort (peer1) == BGP_PEER_EBGP) sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); if (! bgp) bgp = peer1->bgp; /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_info ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN + 1]; peer = peer_create_accept (bgp); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); peer->su = su; peer->fd = bgp_sock; peer->status = Active; peer->local_id = peer1->local_id; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = strdup (buf); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; }
/* 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; }
/* 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; }
static int bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) { struct stream *s; int ret; u_int16_t length, command __attribute__((unused)); u_char version, marker; int nbytes __attribute__((unused)); struct in_addr addr __attribute__((unused)); struct in_addr nexthop; u_int32_t metric = 0; u_char nexthop_num; u_char nexthop_type; /* If lookup connection is not available return valid. */ if (zlookup->sock < 0) { if (igpmetric) *igpmetric = 0; return 1; } /* Send query to the lookup connection */ s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP); stream_putc (s, p->prefixlen); stream_put_in_addr (s, &p->u.prefix4); stream_putw_at (s, 0, stream_get_endp (s)); /* Write the packet. */ ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return 1; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return 1; } /* Get result. */ stream_reset (s); /* Fetch length. */ /* XXX: not using nbytes */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); /* Fetch whole data. */ nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return 0; } /* XXX: not using command */ command = stream_getw (s); /* XXX: not using addr */ addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); /* Set IGP metric value. */ if (igpmetric) *igpmetric = metric; /* If there is nexthop then this is active route. */ if (nexthop_num) { nexthop.s_addr = 0; nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); /* ifindex */ (void)stream_getl (s); break; default: /* do nothing */ break; } *igpnexthop = nexthop; return 1; } else 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; }
/* 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); }
struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) { struct pim_interface *pim_ifp; zassert(ifp); zassert(!ifp->info); pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); if (!pim_ifp) { zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp)); return 0; } pim_ifp->options = 0; pim_ifp->mroute_vif_index = -1; pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC; /* RFC 3376: 8.3. Query Response Interval The number of seconds represented by the [Query Response Interval] must be less than the [Query Interval]. */ zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval); if (pim) PIM_IF_DO_PIM(pim_ifp->options); if (igmp) PIM_IF_DO_IGMP(pim_ifp->options); #if 0 /* FIXME: Should join? */ PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); #endif pim_ifp->igmp_join_list = 0; pim_ifp->igmp_socket_list = 0; pim_ifp->pim_neighbor_list = 0; pim_ifp->pim_ifchannel_list = 0; /* list of struct igmp_sock */ pim_ifp->igmp_socket_list = list_new(); if (!pim_ifp->igmp_socket_list) { zlog_err("%s %s: failure: igmp_socket_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free; /* list of struct pim_neighbor */ pim_ifp->pim_neighbor_list = list_new(); if (!pim_ifp->pim_neighbor_list) { zlog_err("%s %s: failure: pim_neighbor_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free; /* list of struct pim_ifchannel */ pim_ifp->pim_ifchannel_list = list_new(); if (!pim_ifp->pim_ifchannel_list) { zlog_err("%s %s: failure: pim_ifchannel_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; ifp->info = pim_ifp; pim_sock_reset(ifp); zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options)); if (PIM_MROUTE_IS_ENABLED) { pim_if_add_vif(ifp); } return pim_ifp; }
void isis_zebra_route_del_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv6 api; struct in6_addr **nexthop_list; unsigned int *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; struct prefix_ipv6 prefix6; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) return; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.nexthop_num = listcount (route_info->nexthops6); api.ifindex_num = listcount (route_info->nexthops6); /* allocate memory for nexthop_list */ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6); nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size); if (!nexthop_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); return; } /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); XFREE (MTYPE_ISIS_TMP, nexthop_list); return; } /* for each nexthop */ i = 0; for (node = listhead (route_info->nexthops6); node; nextnode (node)) { nexthop6 = getdata (node); if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) && !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) { api.nexthop_num--; api.ifindex_num--; continue; } nexthop_list[i] = &nexthop6->ip6; ifindex_list[i] = nexthop6->ifindex; i++; } api.nexthop = nexthop_list; api.ifindex = ifindex_list; if (api.nexthop_num && api.ifindex_num) { prefix6.family = AF_INET6; prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, &api); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); } XFREE (MTYPE_ISIS_TMP, nexthop_list); XFREE (MTYPE_ISIS_TMP, ifindex_list); }
static int if_getaddrs (void) { int ret; struct ifaddrs *ifap; struct ifaddrs *ifapfree; struct interface *ifp; int prefixlen; ret = getifaddrs (&ifap); if (ret != 0) { zlog_err ("getifaddrs(): %s", safe_strerror (errno)); return -1; } for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) { if (ifap->ifa_addr == NULL) { zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s", __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)")); continue; } ifp = if_lookup_by_name (ifap->ifa_name); if (ifp == NULL) { zlog_err ("if_getaddrs(): Can't lookup interface %s\n", ifap->ifa_name); continue; } if (ifap->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr; struct sockaddr_in *mask; struct sockaddr_in *dest; struct in_addr *dest_pnt; addr = (struct sockaddr_in *) ifap->ifa_addr; mask = (struct sockaddr_in *) ifap->ifa_netmask; prefixlen = ip_masklen (mask->sin_addr); dest_pnt = NULL; if (ifap->ifa_flags & IFF_POINTOPOINT) { dest = (struct sockaddr_in *) ifap->ifa_dstaddr; dest_pnt = &dest->sin_addr; } if (ifap->ifa_flags & IFF_BROADCAST) { dest = (struct sockaddr_in *) ifap->ifa_broadaddr; dest_pnt = &dest->sin_addr; } connected_add_ipv4 (ifp, 0, &addr->sin_addr, prefixlen, dest_pnt, NULL); } #ifdef HAVE_IPV6 if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; struct sockaddr_in6 *mask; struct sockaddr_in6 *dest; struct in6_addr *dest_pnt; addr = (struct sockaddr_in6 *) ifap->ifa_addr; mask = (struct sockaddr_in6 *) ifap->ifa_netmask; prefixlen = ip6_masklen (mask->sin6_addr); dest_pnt = NULL; if (ifap->ifa_flags & IFF_POINTOPOINT) { if (ifap->ifa_dstaddr) { dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; dest_pnt = &dest->sin6_addr; } } if (ifap->ifa_flags & IFF_BROADCAST) { if (ifap->ifa_broadaddr) { dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; dest_pnt = &dest->sin6_addr; } } #if defined(KAME) if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { addr->sin6_scope_id = ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]); addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0; } #endif connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt, NULL); } #endif /* HAVE_IPV6 */ } freeifaddrs (ifapfree); return 0; }
/* Send router advertisement packet. */ static void rtadv_send_packet (int sock, struct interface *ifp) { struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_pktinfo *pkt; struct sockaddr_in6 addr; #ifdef HAVE_STRUCT_SOCKADDR_DL struct sockaddr_dl *sdl; #endif /* HAVE_STRUCT_SOCKADDR_DL */ static void *adata = NULL; unsigned char buf[RTADV_MSG_SIZE]; struct nd_router_advert *rtadv; int ret; int len = 0; struct zebra_if *zif; struct rtadv_prefix *rprefix; u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; struct listnode *node; /* * Allocate control message bufffer. This is dynamic because * CMSG_SPACE is not guaranteed not to call a function. Note that * the size will be different on different architectures due to * differing alignment rules. */ if (adata == NULL) { /* XXX Free on shutdown. */ adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo))); if (adata == NULL) zlog_err("rtadv_send_packet: can't malloc control data\n"); } /* Logging of packet. */ if (IS_ZEBRA_DEBUG_PACKET) zlog_debug ("Router advertisement send to %s", ifp->name); /* Fill in sockaddr_in6. */ memset (&addr, 0, sizeof (struct sockaddr_in6)); addr.sin6_family = AF_INET6; #ifdef SIN6_LEN addr.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ addr.sin6_port = htons (IPPROTO_ICMPV6); memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr)); /* Fetch interface information. */ zif = ifp->info; /* Make router advertisement message. */ rtadv = (struct nd_router_advert *) buf; rtadv->nd_ra_type = ND_ROUTER_ADVERT; rtadv->nd_ra_code = 0; rtadv->nd_ra_cksum = 0; rtadv->nd_ra_curhoplimit = 64; /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */ rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference; rtadv->nd_ra_flags_reserved <<= 3; if (zif->rtadv.AdvManagedFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; if (zif->rtadv.AdvOtherConfigFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; if (zif->rtadv.AdvHomeAgentFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime); rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime); rtadv->nd_ra_retransmit = htonl (0); len = sizeof (struct nd_router_advert); if (zif->rtadv.AdvHomeAgentFlag) { struct nd_opt_homeagent_info *ndopt_hai = (struct nd_opt_homeagent_info *)(buf + len); ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference); ndopt_hai->nd_opt_hai_lifetime = htons(zif->rtadv.HomeAgentLifetime); len += sizeof(struct nd_opt_homeagent_info); } if (zif->rtadv.AdvIntervalOption) { struct nd_opt_adv_interval *ndopt_adv = (struct nd_opt_adv_interval *)(buf + len); ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL; ndopt_adv->nd_opt_ai_len = 1; ndopt_adv->nd_opt_ai_reserved = 0; ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval); len += sizeof(struct nd_opt_adv_interval); } /* Fill in prefix. */ for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { struct nd_opt_prefix_info *pinfo; pinfo = (struct nd_opt_prefix_info *) (buf + len); pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; pinfo->nd_opt_pi_len = 4; pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen; pinfo->nd_opt_pi_flags_reserved = 0; if (rprefix->AdvOnLinkFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; if (rprefix->AdvAutonomousFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; if (rprefix->AdvRouterAddressFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR; pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime); pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime); pinfo->nd_opt_pi_reserved2 = 0; memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6, sizeof (struct in6_addr)); #ifdef DEBUG { u_char buf[INET6_ADDRSTRLEN]; zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN)); } #endif /* DEBUG */ len += sizeof (struct nd_opt_prefix_info); } /* Hardware address. */ #ifdef HAVE_STRUCT_SOCKADDR_DL sdl = &ifp->sdl; if (sdl != NULL && sdl->sdl_alen != 0) { buf[len++] = ND_OPT_SOURCE_LINKADDR; /* Option length should be rounded up to next octet if the link address does not end on an octet boundary. */ buf[len++] = (sdl->sdl_alen + 9) >> 3; memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen); len += sdl->sdl_alen; /* Pad option to end on an octet boundary. */ memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7); len += -(sdl->sdl_alen + 2) & 0x7; }
/* Receive message from netlink interface and pass those information to the given function. */ static int netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), struct nlsock *nl) { int status; int ret = 0; int error; while (1) { char buf[NL_PKT_BUF_SIZE]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; struct nlmsghdr *h; status = recvmsg (nl->sock, &msg, 0); if (status < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) break; zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s", nl->name, safe_strerror(errno)); continue; } if (status == 0) { zlog (NULL, LOG_ERR, "%s EOF", nl->name); return -1; } if (msg.msg_namelen != sizeof snl) { zlog (NULL, LOG_ERR, "%s sender address length error: length %d", nl->name, msg.msg_namelen); return -1; } for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status); h = NLMSG_NEXT (h, status)) { /* Finish of reading. */ if (h->nlmsg_type == NLMSG_DONE) return ret; /* Error handling. */ if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h); int errnum = err->error; int msg_type = err->msg.nlmsg_type; /* If the error field is zero, then this is an ACK */ if (err->error == 0) { if (IS_DEBUG_HA(kroute, KROUTE)) { zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u", __FUNCTION__, nl->name, lookup (nlmsg_str, err->msg.nlmsg_type), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); } /* return if not a multipart message, otherwise continue */ if (!(h->nlmsg_flags & NLM_F_MULTI)) { return 0; } continue; } if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) { zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); return -1; } /* Deal with errors that occur because of races in link handling */ if (nl == &netlink_cmd && ((msg_type == RTM_DELROUTE && (-errnum == ENODEV || -errnum == ESRCH)) || (msg_type == RTM_NEWROUTE && -errnum == EEXIST))) { if (IS_DEBUG_HA(kroute, KROUTE)) zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u", nl->name, safe_strerror (-errnum), lookup (nlmsg_str, msg_type), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return 0; } zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u", nl->name, safe_strerror (-errnum), lookup (nlmsg_str, msg_type), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return -1; } /* OK we got netlink message. */ if (IS_DEBUG_HA(kroute, KROUTE)) zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u", nl->name, lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, h->nlmsg_seq, h->nlmsg_pid); /* skip unsolicited messages originating from command socket */ if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid) { if (IS_DEBUG_HA(kroute, KROUTE)) zlog_debug ("netlink_parse_info: %s packet comes from %s", netlink_cmd.name, nl->name); continue; } error = (*filter) (&snl, h); if (error < 0) { zlog (NULL, LOG_ERR, "%s filter function error", nl->name); ret = error; } } /* After error care. */ if (msg.msg_flags & MSG_TRUNC) { zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); continue; } if (status) { zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name, status); return -1; } } return ret; }
/* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; /* Register accept thread. */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } set_nonblocking (bgp_sock); /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(bgp_sock); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); if (! peer1 || peer1->status == Idle) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) zlog_debug ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else zlog_debug ("[Event] BGP connection IP address %s is Idle state", inet_sutop (&su, buf)); } close (bgp_sock); return -1; } bgp_set_socket_ttl (peer1, bgp_sock); /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN]; peer = peer_create_accept (peer1->bgp); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); peer->su = su; peer->fd = bgp_sock; peer->status = Active; peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); } BGP_EVENT_ADD (peer, TCP_connection_open); 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; }
static struct bgp_nexthop_cache * zlookup_read (void) { struct stream *s; uint16_t length; u_char marker; u_char version; uint16_t command; int nbytes; struct in_addr raddr; uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } command = stream_getw (s); raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; }
static int zclient_read_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { int num_ifindex = 0; struct stream *s; const uint16_t MIN_LEN = 14; /* getc=1 getc=1 getw=2 getipv4=4 getc=1 getl=4 getc=1 */ uint16_t length, len; u_char marker; u_char version; uint16_t command; int nbytes; struct in_addr raddr; uint8_t distance; uint32_t metric; int nexthop_num; int i; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); } s = zlookup->ibuf; stream_reset(s); nbytes = stream_read(s, zlookup->sock, 2); if (nbytes < 2) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d", __FILE__, __PRETTY_FUNCTION__, nbytes); zclient_lookup_failed(zlookup); return -1; } length = stream_getw(s); len = length - 2; if (len < MIN_LEN) { zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", __FILE__, __PRETTY_FUNCTION__, len, MIN_LEN); zclient_lookup_failed(zlookup); return -2; } nbytes = stream_read(s, zlookup->sock, len); if (nbytes < (length - 2)) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d", __FILE__, __PRETTY_FUNCTION__, nbytes, len); zclient_lookup_failed(zlookup); return -3; } marker = stream_getc(s); version = stream_getc(s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return -4; } command = stream_getw(s); if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); return -5; } raddr.s_addr = stream_get_ipv4(s); if (raddr.s_addr != addr.s_addr) { char addr_str[100]; char raddr_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str)); zlog_warn("%s: address mismatch: addr=%s raddr=%s", __PRETTY_FUNCTION__, addr_str, raddr_str); /* warning only */ } distance = stream_getc(s); metric = stream_getl(s); nexthop_num = stream_getc(s); if (nexthop_num < 1) { zlog_err("%s: socket %d bad nexthop_num=%d", __func__, zlookup->sock, nexthop_num); return -6; } len -= MIN_LEN; for (i = 0; i < nexthop_num; ++i) { enum nexthop_types_t nexthop_type; if (len < 1) { zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d", __func__, zlookup->sock, len); return -7; } nexthop_type = stream_getc(s); --len; switch (nexthop_type) { case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: case ZEBRA_NEXTHOP_IPV4_IFINDEX: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", __FILE__, __PRETTY_FUNCTION__, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { if (len < 4) { zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d", __func__, zlookup->sock, len); return -8; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); len -= 4; } else { nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY; } nexthop_tab[num_ifindex].ifindex = stream_getl(s); nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; ++num_ifindex; break; case ZEBRA_NEXTHOP_IPV4: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", __FILE__, __PRETTY_FUNCTION__, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); len -= 4; nexthop_tab[num_ifindex].ifindex = 0; nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<nexthop?>", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_warn("%s %s: zebra returned recursive nexthop %s for address %s", __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str); } ++num_ifindex; break; default: /* do nothing */ { char addr_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s", __FILE__, __PRETTY_FUNCTION__, nexthop_type, addr_str); } break; } } return num_ifindex; }