Beispiel #1
0
/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
   names and ifindex values. */
static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
			struct zebra_ns *zns)
{
	struct interface *oifp;

	if (((oifp = if_lookup_by_index_per_ns(zns, ifi_index)) != NULL)
	    && (oifp != ifp)) {
		if (ifi_index == IFINDEX_INTERNAL)
			flog_err(
				LIB_ERR_INTERFACE,
				"Netlink is setting interface %s ifindex to reserved internal value %u",
				ifp->name, ifi_index);
		else {
			if (IS_ZEBRA_DEBUG_KERNEL)
				zlog_debug(
					"interface index %d was renamed from %s to %s",
					ifi_index, oifp->name, ifp->name);
			if (if_is_up(oifp))
				flog_err(
					LIB_ERR_INTERFACE,
					"interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!",
					ifi_index, oifp->name, ifp->name);
			if_delete_update(oifp);
		}
	}
	if_set_index(ifp, ifi_index);
}
Beispiel #2
0
int bgp_set_socket_ttl(struct peer *peer, int bgp_sock)
{
	char buf[INET_ADDRSTRLEN];
	int ret = 0;

	/* In case of peer is EBGP, we should set TTL for this connection.  */
	if (!peer->gtsm_hops && (peer_sort(peer) == BGP_PEER_EBGP)) {
		ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl);
		if (ret) {
			flog_err(
				EC_LIB_SOCKET,
				"%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
				__func__,
				inet_ntop(AF_INET, &peer->remote_id, buf,
					  sizeof(buf)),
				errno);
			return ret;
		}
	} else if (peer->gtsm_hops) {
		/* On Linux, setting minttl without setting ttl seems to mess
		   with the
		   outgoing ttl. Therefore setting both.
		*/
		ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, MAXTTL);
		if (ret) {
			flog_err(
				EC_LIB_SOCKET,
				"%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
				__func__,
				inet_ntop(AF_INET, &peer->remote_id, buf,
					  sizeof(buf)),
				errno);
			return ret;
		}
		ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock,
				     MAXTTL + 1 - peer->gtsm_hops);
		if (ret) {
			flog_err(
				EC_LIB_SOCKET,
				"%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d",
				__func__,
				inet_ntop(AF_INET, &peer->remote_id, buf,
					  sizeof(buf)),
				errno);
			return ret;
		}
	}

	return ret;
}
Beispiel #3
0
/* After TCP connection is established.  Get local address and port. */
int bgp_getsockname(struct peer *peer)
{
	if (peer->su_local) {
		sockunion_free(peer->su_local);
		peer->su_local = NULL;
	}

	if (peer->su_remote) {
		sockunion_free(peer->su_remote);
		peer->su_remote = NULL;
	}

	peer->su_local = sockunion_getsockname(peer->fd);
	if (!peer->su_local)
		return -1;
	peer->su_remote = sockunion_getpeername(peer->fd);
	if (!peer->su_remote)
		return -1;

	if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote,
				   &peer->nexthop, peer)) {
		flog_err(EC_BGP_NH_UPD,
			 "%s: nexthop_set failed, resetting connection - intf %p",
			 peer->host, peer->nexthop.ifp);
		return -1;
	}
	return 0;
}
Beispiel #4
0
/* we need to be very cautious with this API as SA del too can trigger an
 * upstream del and we will get stuck in a simple loop */
static void pim_msdp_sa_local_del_on_up_del(struct pim_instance *pim,
					    struct prefix_sg *sg)
{
	struct pim_msdp_sa *sa;

	sa = pim_msdp_sa_find(pim, sg);
	if (sa) {
		if (PIM_DEBUG_MSDP_INTERNAL) {
			zlog_debug("MSDP local sa %s del on up del",
				   sa->sg_str);
		}

		/* if there is no local reference escape */
		if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
			if (PIM_DEBUG_MSDP_INTERNAL) {
				zlog_debug("MSDP local sa %s del; no local ref",
					   sa->sg_str);
			}
			return;
		}

		if (sa->flags & PIM_MSDP_SAF_UP_DEL_IN_PROG) {
			/* MSDP is the one that triggered the upstream del. if
			 * this happens
			 * we most certainly have a bug in the PIM upstream
			 * state machine. We
			 * will not have a local reference unless the KAT is
			 * running. And if the
			 * KAT is running there MUST be an additional
			 * source-stream reference to
			 * the flow. Accounting for such cases requires lot of
			 * changes; perhaps
			 * address this in the next release? - XXX  */
			flog_err(
				EC_LIB_DEVELOPMENT,
				"MSDP sa %s SPT teardown is causing the local entry to be removed",
				sa->sg_str);
			return;
		}

		/* we are dropping the sa on upstream del we should not have an
		 * upstream reference */
		if (sa->up) {
			if (PIM_DEBUG_MSDP_INTERNAL) {
				zlog_debug("MSDP local sa %s del; up non-NULL",
					   sa->sg_str);
			}
			sa->up = NULL;
		}
		pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL);
	}
}
Beispiel #5
0
void
install_route(struct babel_route *route)
{
    int i, rc;

    if(route->installed)
        return;

    if(!route_feasible(route))
        flog_err(EC_BABEL_ROUTE, "WARNING: installing unfeasible route "
                  "(this shouldn't happen).");

    i = find_route_slot(route->src->prefix, route->src->plen, NULL);
    assert(i >= 0 && i < route_slots);

    if(routes[i] != route && routes[i]->installed) {
        flog_err(EC_BABEL_ROUTE,
		  "WARNING: attempting to install duplicate route "
                  "(this shouldn't happen).");
        return;
    }

    rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
                      route->nexthop,
                      route->neigh->ifp->ifindex,
                      metric_to_kernel(route_metric(route)), NULL, 0, 0);
    if(rc < 0) {
        int save = errno;
        flog_err(EC_BABEL_ROUTE, "kernel_route(ADD): %s",
		  safe_strerror(errno));
        if(save != EEXIST)
            return;
    }
    route->installed = 1;
    move_installed_route(route, i);

}
Beispiel #6
0
void
uninstall_route(struct babel_route *route)
{
    int rc;

    if(!route->installed)
        return;

    rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen,
                      route->nexthop,
                      route->neigh->ifp->ifindex,
                      metric_to_kernel(route_metric(route)), NULL, 0, 0);
    if(rc < 0)
        flog_err(EC_BABEL_ROUTE, "kernel_route(FLUSH): %s",
		  safe_strerror(errno));

    route->installed = 0;
}
Beispiel #7
0
struct source*
find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
            int create, unsigned short seqno)
{
    struct source *src;

    for(src = srcs; src; src = src->next) {
        /* This should really be a hash table.  For now, check the
           last byte first. */
        if(src->id[7] != id[7])
            continue;
        if(memcmp(src->id, id, 8) != 0)
            continue;
        if(src->plen != plen)
            continue;
        if(memcmp(src->prefix, p, 16) == 0)
            return src;
    }

    if(!create)
        return NULL;

    src = malloc(sizeof(struct source));
    if(src == NULL) {
        flog_err(BABEL_ERR_MEMORY, "malloc(source): %s", safe_strerror(errno));
        return NULL;
    }

    memcpy(src->id, id, 8);
    memcpy(src->prefix, p, 16);
    src->plen = plen;
    src->seqno = seqno;
    src->metric = INFINITY;
    src->time = babel_now.tv_sec;
    src->route_count = 0;
    src->next = srcs;
    srcs = src;
    return src;
}
Beispiel #8
0
/* passive peer socket accept */
static int pim_msdp_sock_accept(struct thread *thread)
{
	union sockunion su;
	struct pim_instance *pim = THREAD_ARG(thread);
	int accept_sock;
	int msdp_sock;
	struct pim_msdp_peer *mp;
	char buf[SU_ADDRSTRLEN];

	sockunion_init(&su);

	/* re-register accept thread */
	accept_sock = THREAD_FD(thread);
	if (accept_sock < 0) {
		flog_err(LIB_ERR_DEVELOPMENT,
			  "accept_sock is negative value %d", accept_sock);
		return -1;
	}
	pim->msdp.listener.thread = NULL;
	thread_add_read(master, pim_msdp_sock_accept, pim, accept_sock,
			&pim->msdp.listener.thread);

	/* accept client connection. */
	msdp_sock = sockunion_accept(accept_sock, &su);
	if (msdp_sock < 0) {
		flog_err_sys(LIB_ERR_SOCKET, "pim_msdp_sock_accept failed (%s)",
			     safe_strerror(errno));
		return -1;
	}

	/* see if have peer config for this */
	mp = pim_msdp_peer_find(pim, su.sin.sin_addr);
	if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
		++pim->msdp.rejected_accepts;
		if (PIM_DEBUG_MSDP_EVENTS) {
			flog_err(PIM_ERR_MSDP_PACKET,
				  "msdp peer connection refused from %s",
				  sockunion2str(&su, buf, SU_ADDRSTRLEN));
		}
		close(msdp_sock);
		return -1;
	}

	if (PIM_DEBUG_MSDP_INTERNAL) {
		zlog_debug("MSDP peer %s accept success%s", mp->key_str,
			   mp->fd >= 0 ? "(dup)" : "");
	}

	/* if we have an existing connection we need to kill that one
	 * with this one */
	if (mp->fd >= 0) {
		if (PIM_DEBUG_MSDP_EVENTS) {
			zlog_notice(
				"msdp peer new connection from %s stop old connection",
				sockunion2str(&su, buf, SU_ADDRSTRLEN));
		}
		pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
	}
	mp->fd = msdp_sock;
	set_nonblocking(mp->fd);
	pim_msdp_update_sock_send_buffer_size(mp->fd);
	pim_msdp_peer_established(mp);
	return 0;
}
Beispiel #9
0
/* active peer socket setup */
int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
{
	int rc;

	if (PIM_DEBUG_MSDP_INTERNAL) {
		zlog_debug("MSDP peer %s attempt connect%s", mp->key_str,
			   mp->fd < 0 ? "" : "(dup)");
	}

	/* if we have an existing connection we need to kill that one
	 * with this one */
	if (mp->fd >= 0) {
		if (PIM_DEBUG_MSDP_EVENTS) {
			zlog_notice(
				"msdp duplicate connect to %s nuke old connection",
				mp->key_str);
		}
		pim_msdp_peer_stop_tcp_conn(mp, false /* chg_state */);
	}

	/* Make socket for the peer. */
	mp->fd = sockunion_socket(&mp->su_peer);
	if (mp->fd < 0) {
		flog_err_sys(LIB_ERR_SOCKET,
			     "pim_msdp_socket socket failure: %s",
			     safe_strerror(errno));
		return -1;
	}

	if (mp->pim->vrf_id != VRF_DEFAULT) {
		struct interface *ifp =
			if_lookup_by_name(mp->pim->vrf->name, mp->pim->vrf_id);
		if (!ifp) {
			flog_err(LIB_ERR_INTERFACE,
				  "%s: Unable to lookup vrf interface: %s",
				  __PRETTY_FUNCTION__, mp->pim->vrf->name);
			return -1;
		}
		if (pim_socket_bind(mp->fd, ifp)) {
			flog_err_sys(LIB_ERR_SOCKET,
				     "%s: Unable to bind to socket: %s",
				     __PRETTY_FUNCTION__, safe_strerror(errno));
			close(mp->fd);
			mp->fd = -1;
			return -1;
		}
	}

	set_nonblocking(mp->fd);

	/* Set socket send buffer size */
	pim_msdp_update_sock_send_buffer_size(mp->fd);
	sockopt_reuseaddr(mp->fd);
	sockopt_reuseport(mp->fd);

	/* source bind */
	rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
	if (rc < 0) {
		flog_err_sys(LIB_ERR_SOCKET,
			     "pim_msdp_socket connect bind failure: %s",
			     safe_strerror(errno));
		close(mp->fd);
		mp->fd = -1;
		return rc;
	}

	/* Connect to the remote mp. */
	return (sockunion_connect(mp->fd, &mp->su_peer,
				  htons(PIM_MSDP_TCP_PORT), 0));
}
Beispiel #10
0
/* global listener for the MSDP well know TCP port */
int pim_msdp_sock_listen(struct pim_instance *pim)
{
	int sock;
	int socklen;
	struct sockaddr_in sin;
	int rc;
	struct pim_msdp_listener *listener = &pim->msdp.listener;

	if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
		/* listener already setup */
		return 0;
	}

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0) {
		flog_err_sys(LIB_ERR_SOCKET, "socket: %s",
			     safe_strerror(errno));
		return sock;
	}

	memset(&sin, 0, sizeof(struct sockaddr_in));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PIM_MSDP_TCP_PORT);
	socklen = sizeof(struct sockaddr_in);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
	sin.sin_len = socklen;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */

	sockopt_reuseaddr(sock);
	sockopt_reuseport(sock);

	if (pim->vrf_id != VRF_DEFAULT) {
		struct interface *ifp =
			if_lookup_by_name(pim->vrf->name, pim->vrf_id);
		if (!ifp) {
			flog_err(LIB_ERR_INTERFACE,
				  "%s: Unable to lookup vrf interface: %s",
				  __PRETTY_FUNCTION__, pim->vrf->name);
			close(sock);
			return -1;
		}
		if (pim_socket_bind(sock, ifp)) {
			flog_err_sys(LIB_ERR_SOCKET,
				     "%s: Unable to bind to socket: %s",
				     __PRETTY_FUNCTION__, safe_strerror(errno));
			close(sock);
			return -1;
		}
	}

	frr_elevate_privs(&pimd_privs) {
		/* bind to well known TCP port */
		rc = bind(sock, (struct sockaddr *)&sin, socklen);
	}

	if (rc < 0) {
		flog_err_sys(LIB_ERR_SOCKET,
			     "pim_msdp_socket bind to port %d: %s",
			     ntohs(sin.sin_port), safe_strerror(errno));
		close(sock);
		return rc;
	}

	rc = listen(sock, 3 /* backlog */);
	if (rc < 0) {
		flog_err_sys(LIB_ERR_SOCKET, "pim_msdp_socket listen: %s",
			     safe_strerror(errno));
		close(sock);
		return rc;
	}

	/* add accept thread */
	listener->fd = sock;
	memcpy(&listener->su, &sin, socklen);
	listener->thread = NULL;
	thread_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
			&listener->thread);

	pim->msdp.flags |= PIM_MSDPF_LISTENER;
	return 0;
}
Beispiel #11
0
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;
}
Beispiel #12
0
static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
{
	struct sockaddr_in sockaddr;
	int fd;

	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fd < 0) {
		flog_err_sys(LIB_ERR_SOCKET,
			     "%s: could not create socket: errno=%d: %s",
			     __PRETTY_FUNCTION__, errno, safe_strerror(errno));
		return -1;
	}

	sockaddr.sin_family = AF_INET;
	sockaddr.sin_addr = addr;
	sockaddr.sin_port = htons(port);

	if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
		char addr_str[INET_ADDRSTRLEN];
		pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
		zlog_warn(
			"%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s",
			__PRETTY_FUNCTION__, fd, addr_str, port,
			sizeof(sockaddr), errno, safe_strerror(errno));
		close(fd);
		return -1;
	}

	/* Needed to obtain destination address from recvmsg() */
	{
#if defined(HAVE_IP_PKTINFO)
		/* Linux and Solaris IP_PKTINFO */
		int opt = 1;
		if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
			zlog_warn(
				"%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
				__PRETTY_FUNCTION__, fd, errno,
				safe_strerror(errno));
		}
#elif defined(HAVE_IP_RECVDSTADDR)
		/* BSD IP_RECVDSTADDR */
		int opt = 1;
		if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt,
			       sizeof(opt))) {
			zlog_warn(
				"%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
				__PRETTY_FUNCTION__, fd, errno,
				safe_strerror(errno));
		}
#else
		flog_err(
			LIB_ERR_DEVELOPMENT,
			"%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
			__FILE__, __PRETTY_FUNCTION__);
		close(fd);
		return -1;
#endif
	}

	{
		int reuse = 1;
		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse,
			       sizeof(reuse))) {
			zlog_warn(
				"%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
				__PRETTY_FUNCTION__, fd, errno,
				safe_strerror(errno));
			close(fd);
			return -1;
		}
	}

	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&mttl,
		       sizeof(mttl))) {
		zlog_warn(
			"%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
			__PRETTY_FUNCTION__, mttl, fd, errno,
			safe_strerror(errno));
		close(fd);
		return -1;
	}

	if (setsockopt_ipv4_multicast_loop(fd, 0)) {
		zlog_warn(
			"%s: could not disable Multicast Loopback Option on socket fd=%d: errno=%d: %s",
			__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
		close(fd);
		return PIM_SOCK_ERR_LOOP;
	}

	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&addr,
		       sizeof(addr))) {
		zlog_warn(
			"%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
			__PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
		close(fd);
		return -1;
	}

	{
		long flags;

		flags = fcntl(fd, F_GETFL, 0);
		if (flags < 0) {
			zlog_warn(
				"%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
				__PRETTY_FUNCTION__, fd, errno,
				safe_strerror(errno));
			close(fd);
			return -1;
		}

		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
			zlog_warn(
				"%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
				__PRETTY_FUNCTION__, fd, errno,
				safe_strerror(errno));
			close(fd);
			return -1;
		}
	}

	return fd;
}
Beispiel #13
0
/* IPv6 supported version of BGP server socket setup.  */
int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
{
	struct addrinfo *ainfo;
	struct addrinfo *ainfo_save;
	static const struct addrinfo req = {
		.ai_family = AF_UNSPEC,
		.ai_flags = AI_PASSIVE,
		.ai_socktype = SOCK_STREAM,
	};
	int ret, count;
	char port_str[BUFSIZ];

	snprintf(port_str, sizeof(port_str), "%d", port);
	port_str[sizeof(port_str) - 1] = '\0';

	frr_elevate_privs(&bgpd_privs) {
		ret = vrf_getaddrinfo(address, port_str, &req, &ainfo_save,
				      bgp->vrf_id);
	}
	if (ret != 0) {
		flog_err_sys(EC_LIB_SOCKET, "getaddrinfo: %s",
			     gai_strerror(ret));
		return -1;
	}
	if (bgp_option_check(BGP_OPT_NO_ZEBRA) &&
	    bgp->vrf_id != VRF_DEFAULT) {
		freeaddrinfo(ainfo_save);
		return -1;
	}
	count = 0;
	for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next) {
		int sock;

		if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
			continue;

		frr_elevate_privs(&bgpd_privs) {
			sock = vrf_socket(ainfo->ai_family,
					  ainfo->ai_socktype,
					  ainfo->ai_protocol, bgp->vrf_id,
					  (bgp->inst_type
					   == BGP_INSTANCE_TYPE_VRF
					   ? bgp->name : NULL));
		}
		if (sock < 0) {
			flog_err_sys(EC_LIB_SOCKET, "socket: %s",
				     safe_strerror(errno));
			continue;
		}

		/* if we intend to implement ttl-security, this socket needs
		 * ttl=255 */
		sockopt_ttl(ainfo->ai_family, sock, MAXTTL);

		ret = bgp_listener(sock, ainfo->ai_addr, ainfo->ai_addrlen,
				   bgp);
		if (ret == 0)
			++count;
		else
			close(sock);
	}
	freeaddrinfo(ainfo_save);
	if (count == 0 && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) {
		flog_err(
			EC_LIB_SOCKET,
			"%s: no usable addresses please check other programs usage of specified port %d",
			__func__, port);
		flog_err_sys(EC_LIB_SOCKET, "%s: Program cannot continue",
			     __func__);
		exit(-1);
	}

	return 0;
}
Beispiel #14
0
int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
	int len;
	struct ifaddrmsg *ifa;
	struct rtattr *tb[IFA_MAX + 1];
	struct interface *ifp;
	void *addr;
	void *broad;
	uint8_t flags = 0;
	char *label = NULL;
	struct zebra_ns *zns;

	zns = zebra_ns_lookup(ns_id);
	ifa = NLMSG_DATA(h);

	if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
		zlog_warn(
			"Invalid address family: %u received from kernel interface addr change: %u",
			ifa->ifa_family, h->nlmsg_type);
		return 0;
	}

	if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	if (len < 0) {
		zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
			 __PRETTY_FUNCTION__,
			 h->nlmsg_len,
			 (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg)));
		return -1;
	}

	memset(tb, 0, sizeof tb);
	netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);

	ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index);
	if (ifp == NULL) {
		flog_err(
			LIB_ERR_INTERFACE,
			"netlink_interface_addr can't find interface by index %d",
			ifa->ifa_index);
		return -1;
	}

	if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
	{
		char buf[BUFSIZ];
		zlog_debug("netlink_interface_addr %s %s flags 0x%x:",
			   nl_msg_type_to_str(h->nlmsg_type), ifp->name,
			   ifa->ifa_flags);
		if (tb[IFA_LOCAL])
			zlog_debug("  IFA_LOCAL     %s/%d",
				   inet_ntop(ifa->ifa_family,
					     RTA_DATA(tb[IFA_LOCAL]), buf,
					     BUFSIZ),
				   ifa->ifa_prefixlen);
		if (tb[IFA_ADDRESS])
			zlog_debug("  IFA_ADDRESS   %s/%d",
				   inet_ntop(ifa->ifa_family,
					     RTA_DATA(tb[IFA_ADDRESS]), buf,
					     BUFSIZ),
				   ifa->ifa_prefixlen);
		if (tb[IFA_BROADCAST])
			zlog_debug("  IFA_BROADCAST %s/%d",
				   inet_ntop(ifa->ifa_family,
					     RTA_DATA(tb[IFA_BROADCAST]), buf,
					     BUFSIZ),
				   ifa->ifa_prefixlen);
		if (tb[IFA_LABEL] && strcmp(ifp->name, RTA_DATA(tb[IFA_LABEL])))
			zlog_debug("  IFA_LABEL     %s",
				   (char *)RTA_DATA(tb[IFA_LABEL]));

		if (tb[IFA_CACHEINFO]) {
			struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);
			zlog_debug("  IFA_CACHEINFO pref %d, valid %d",
				   ci->ifa_prefered, ci->ifa_valid);
		}
	}

	/* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
	if (tb[IFA_LOCAL] == NULL)
		tb[IFA_LOCAL] = tb[IFA_ADDRESS];
	if (tb[IFA_ADDRESS] == NULL)
		tb[IFA_ADDRESS] = tb[IFA_LOCAL];

	/* local interface address */
	addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);

	/* is there a peer address? */
	if (tb[IFA_ADDRESS]
	    && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]),
		      RTA_PAYLOAD(tb[IFA_ADDRESS]))) {
		broad = RTA_DATA(tb[IFA_ADDRESS]);
		SET_FLAG(flags, ZEBRA_IFA_PEER);
	} else
		/* seeking a broadcast address */
		broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST])
					   : NULL);

	/* addr is primary key, SOL if we don't have one */
	if (addr == NULL) {
		zlog_debug("%s: NULL address", __func__);
		return -1;
	}

	/* Flags. */
	if (ifa->ifa_flags & IFA_F_SECONDARY)
		SET_FLAG(flags, ZEBRA_IFA_SECONDARY);

	/* Label */
	if (tb[IFA_LABEL])
		label = (char *)RTA_DATA(tb[IFA_LABEL]);

	if (label && strcmp(ifp->name, label) == 0)
		label = NULL;

	/* Register interface address to the interface. */
	if (ifa->ifa_family == AF_INET) {
		if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
			zlog_err(
				"Invalid prefix length: %u received from kernel interface addr change: %u",
				ifa->ifa_prefixlen, h->nlmsg_type);
			return -1;
		}
		if (h->nlmsg_type == RTM_NEWADDR)
			connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
					   ifa->ifa_prefixlen,
					   (struct in_addr *)broad, label);
		else
			connected_delete_ipv4(
				ifp, flags, (struct in_addr *)addr,
				ifa->ifa_prefixlen, (struct in_addr *)broad);
	}
	if (ifa->ifa_family == AF_INET6) {
		if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
			zlog_err(
				"Invalid prefix length: %u received from kernel interface addr change: %u",
				ifa->ifa_prefixlen, h->nlmsg_type);
			return -1;
		}
		if (h->nlmsg_type == RTM_NEWADDR) {
			/* Only consider valid addresses; we'll not get a
			 * notification from
			 * the kernel till IPv6 DAD has completed, but at init
			 * time, Quagga
			 * does query for and will receive all addresses.
			 */
			if (!(ifa->ifa_flags
			      & (IFA_F_DADFAILED | IFA_F_TENTATIVE)))
				connected_add_ipv6(ifp, flags,
						   (struct in6_addr *)addr,
						   (struct in6_addr *)broad,
						   ifa->ifa_prefixlen, label);
		} else
			connected_delete_ipv6(ifp, (struct in6_addr *)addr,
					      (struct in6_addr *)broad,
					      ifa->ifa_prefixlen);
	}

	return 0;
}
Beispiel #15
0
/*
 * Obtain the BGP instance that the incoming connection should be processed
 * against. This is important because more than one VRF could be using the
 * same IP address space. The instance is got by obtaining the device to
 * which the incoming connection is bound to. This could either be a VRF
 * or it could be an interface, which in turn determines the VRF.
 */
static int bgp_get_instance_for_inc_conn(int sock, struct bgp **bgp_inst)
{
#ifndef SO_BINDTODEVICE
	/* only Linux has SO_BINDTODEVICE, but we're in Linux-specific code here
	 * anyway since the assumption is that the interface name returned by
	 * getsockopt() is useful in identifying the VRF, particularly with
	 * Linux's
	 * VRF l3master device.  The whole mechanism is specific to Linux, so...
	 * when other platforms add VRF support, this will need handling here as
	 * well.  (or, some restructuring) */
	*bgp_inst = bgp_get_default();
	return !*bgp_inst;

#else
	char name[VRF_NAMSIZ + 1];
	socklen_t name_len = VRF_NAMSIZ;
	struct bgp *bgp;
	int rc;
	struct listnode *node, *nnode;

	*bgp_inst = NULL;
	name[0] = '\0';
	rc = getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, name, &name_len);
	if (rc != 0) {
#if defined(HAVE_CUMULUS)
		flog_err(EC_LIB_SOCKET,
			 "[Error] BGP SO_BINDTODEVICE get failed (%s), sock %d",
			 safe_strerror(errno), sock);
		return -1;
#endif
	}

	if (!strlen(name)) {
		*bgp_inst = bgp_get_default();
		return 0; /* default instance. */
	}

	/* First try match to instance; if that fails, check for interfaces. */
	bgp = bgp_lookup_by_name(name);
	if (bgp) {
		if (!bgp->vrf_id) // unexpected
			return -1;
		*bgp_inst = bgp;
		return 0;
	}

	/* TODO - This will be optimized once interfaces move into the NS */
	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
		struct interface *ifp;

		if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
			continue;

		ifp = if_lookup_by_name(name, bgp->vrf_id);
		if (ifp) {
			*bgp_inst = bgp;
			return 0;
		}
	}

	/* We didn't match to either an instance or an interface. */
	return -1;
#endif
}
Beispiel #16
0
static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
			       const char *name)
{
	struct ifinfomsg *ifi;
	struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
	struct rtattr *attr[IFLA_VRF_MAX + 1];
	struct vrf *vrf;
	struct zebra_vrf *zvrf;
	uint32_t nl_table_id;

	ifi = NLMSG_DATA(h);

	memset(linkinfo, 0, sizeof linkinfo);
	parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);

	if (!linkinfo[IFLA_INFO_DATA]) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug(
				"%s: IFLA_INFO_DATA missing from VRF message: %s",
				__func__, name);
		return;
	}

	memset(attr, 0, sizeof attr);
	parse_rtattr_nested(attr, IFLA_VRF_MAX, linkinfo[IFLA_INFO_DATA]);
	if (!attr[IFLA_VRF_TABLE]) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug(
				"%s: IFLA_VRF_TABLE missing from VRF message: %s",
				__func__, name);
		return;
	}

	nl_table_id = *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE]);

	if (h->nlmsg_type == RTM_NEWLINK) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("RTM_NEWLINK for VRF %s(%u) table %u", name,
				   ifi->ifi_index, nl_table_id);

		/*
		 * vrf_get is implied creation if it does not exist
		 */
		vrf = vrf_get((vrf_id_t)ifi->ifi_index,
			      name); // It would create vrf
		if (!vrf) {
			flog_err(LIB_ERR_INTERFACE, "VRF %s id %u not created",
				  name, ifi->ifi_index);
			return;
		}

		/*
		 * This is the only place that we get the actual kernel table_id
		 * being used.  We need it to set the table_id of the routes
		 * we are passing to the kernel.... And to throw some totally
		 * awesome parties. that too.
		 *
		 * At this point we *must* have a zvrf because the vrf_create
		 * callback creates one.  We *must* set the table id
		 * before the vrf_enable because of( at the very least )
		 * static routes being delayed for installation until
		 * during the vrf_enable callbacks.
		 */
		zvrf = (struct zebra_vrf *)vrf->info;
		zvrf->table_id = nl_table_id;

		/* Enable the created VRF. */
		if (!vrf_enable(vrf)) {
			flog_err(LIB_ERR_INTERFACE,
				  "Failed to enable VRF %s id %u", name,
				  ifi->ifi_index);
			return;
		}

	} else // h->nlmsg_type == RTM_DELLINK
	{
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("RTM_DELLINK for VRF %s(%u)", name,
				   ifi->ifi_index);

		vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index);

		if (!vrf) {
			zlog_warn("%s: vrf not found", __func__);
			return;
		}

		vrf_delete(vrf);
	}
}
Beispiel #17
0
static int frrzmq_read_msg(struct thread *t)
{
	struct frrzmq_cb **cbp = THREAD_ARG(t);
	struct frrzmq_cb *cb;
	zmq_msg_t msg;
	unsigned partno;
	unsigned char read = 0;
	int ret, more;
	size_t moresz;

	if (!cbp)
		return 1;
	cb = (*cbp);
	if (!cb || !cb->zmqsock)
		return 1;

	while (1) {
		zmq_pollitem_t polli = {.socket = cb->zmqsock,
					.events = ZMQ_POLLIN};
		ret = zmq_poll(&polli, 1, 0);

		if (ret < 0)
			goto out_err;

		if (!(polli.revents & ZMQ_POLLIN))
			break;

		if (cb->read.cb_msg) {
			cb->read.cb_msg(cb->read.arg, cb->zmqsock);
			read = 1;

			if (cb->read.cancelled) {
				frrzmq_check_events(cbp, &cb->write,
						    ZMQ_POLLOUT);
				cb->read.thread = NULL;
				if (cb->write.cancelled && !cb->write.thread)
					XFREE(MTYPE_ZEROMQ_CB, cb);
				return 0;
			}
			continue;
		}

		partno = 0;
		if (zmq_msg_init(&msg))
			goto out_err;
		do {
			ret = zmq_msg_recv(&msg, cb->zmqsock, ZMQ_NOBLOCK);
			if (ret < 0) {
				if (errno == EAGAIN)
					break;

				zmq_msg_close(&msg);
				goto out_err;
			}
			read = 1;

			cb->read.cb_part(cb->read.arg, cb->zmqsock, &msg,
					 partno);
			if (cb->read.cancelled) {
				zmq_msg_close(&msg);
				frrzmq_check_events(cbp, &cb->write,
						    ZMQ_POLLOUT);
				cb->read.thread = NULL;
				if (cb->write.cancelled && !cb->write.thread)
					XFREE(MTYPE_ZEROMQ_CB, cb);
				return 0;
			}

			/* cb_part may have read additional parts of the
			 * message; don't use zmq_msg_more here */
			moresz = sizeof(more);
			more = 0;
			ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE, &more,
					     &moresz);
			if (ret < 0) {
				zmq_msg_close(&msg);
				goto out_err;
			}

			partno++;
		} while (more);
		zmq_msg_close(&msg);
	}

	if (read)
		frrzmq_check_events(cbp, &cb->write, ZMQ_POLLOUT);

	funcname_thread_add_read_write(
		THREAD_READ, t->master, frrzmq_read_msg, cbp, cb->fd,
		&cb->read.thread, t->funcname, t->schedfrom, t->schedfrom_line);
	return 0;

out_err:
	flog_err(LIB_ERR_ZMQ, "ZeroMQ read error: %s(%d)", strerror(errno),
		  errno);
	if (cb->read.cb_error)
		cb->read.cb_error(cb->read.arg, cb->zmqsock);
	return 1;
}

int funcname_frrzmq_thread_add_read(struct thread_master *master,
				    void (*msgfunc)(void *arg, void *zmqsock),
				    void (*partfunc)(void *arg, void *zmqsock,
						     zmq_msg_t *msg,
						     unsigned partnum),
				    void (*errfunc)(void *arg, void *zmqsock),
				    void *arg, void *zmqsock,
				    struct frrzmq_cb **cbp, debugargdef)
{
	int fd, events;
	size_t len;
	struct frrzmq_cb *cb;

	if (!cbp)
		return -1;
	if (!(msgfunc || partfunc) || (msgfunc && partfunc))
		return -1;
	len = sizeof(fd);
	if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
		return -1;
	len = sizeof(events);
	if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
		return -1;

	if (*cbp)
		cb = *cbp;
	else {
		cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
		if (!cb)
			return -1;

		cb->write.cancelled = 1;
		*cbp = cb;
	}

	cb->zmqsock = zmqsock;
	cb->fd = fd;
	cb->read.arg = arg;
	cb->read.cb_msg = msgfunc;
	cb->read.cb_part = partfunc;
	cb->read.cb_error = errfunc;
	cb->read.cancelled = 0;

	if (events & ZMQ_POLLIN) {
		if (cb->read.thread) {
			thread_cancel(cb->read.thread);
			cb->read.thread = NULL;
		}
		funcname_thread_add_event(master, frrzmq_read_msg, cbp, fd,
					  &cb->read.thread, funcname, schedfrom,
					  fromln);
	} else
		funcname_thread_add_read_write(
			THREAD_READ, master, frrzmq_read_msg, cbp, fd,
			&cb->read.thread, funcname, schedfrom, fromln);
	return 0;
}
Beispiel #18
0
static int frrzmq_write_msg(struct thread *t)
{
	struct frrzmq_cb **cbp = THREAD_ARG(t);
	struct frrzmq_cb *cb;
	unsigned char written = 0;
	int ret;

	if (!cbp)
		return 1;
	cb = (*cbp);
	if (!cb || !cb->zmqsock)
		return 1;

	while (1) {
		zmq_pollitem_t polli = {.socket = cb->zmqsock,
					.events = ZMQ_POLLOUT};
		ret = zmq_poll(&polli, 1, 0);

		if (ret < 0)
			goto out_err;

		if (!(polli.revents & ZMQ_POLLOUT))
			break;

		if (cb->write.cb_msg) {
			cb->write.cb_msg(cb->write.arg, cb->zmqsock);
			written = 1;

			if (cb->write.cancelled) {
				frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
				cb->write.thread = NULL;
				if (cb->read.cancelled && !cb->read.thread)
					XFREE(MTYPE_ZEROMQ_CB, cb);
				return 0;
			}
			continue;
		}
	}

	if (written)
		frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);

	funcname_thread_add_read_write(THREAD_WRITE, t->master,
				       frrzmq_write_msg, cbp, cb->fd,
				       &cb->write.thread, t->funcname,
				       t->schedfrom, t->schedfrom_line);
	return 0;

out_err:
	flog_err(LIB_ERR_ZMQ, "ZeroMQ write error: %s(%d)", strerror(errno),
		  errno);
	if (cb->write.cb_error)
		cb->write.cb_error(cb->write.arg, cb->zmqsock);
	return 1;
}
int funcname_frrzmq_thread_add_write(struct thread_master *master,
				     void (*msgfunc)(void *arg, void *zmqsock),
				     void (*errfunc)(void *arg, void *zmqsock),
				     void *arg, void *zmqsock,
				     struct frrzmq_cb **cbp, debugargdef)
{
	int fd, events;
	size_t len;
	struct frrzmq_cb *cb;

	if (!cbp)
		return -1;
	if (!msgfunc)
		return -1;
	len = sizeof(fd);
	if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
		return -1;
	len = sizeof(events);
	if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
		return -1;

	if (*cbp)
		cb = *cbp;
	else {
		cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
		if (!cb)
			return -1;

		cb->read.cancelled = 1;
		*cbp = cb;
	}

	cb->zmqsock = zmqsock;
	cb->fd = fd;
	cb->write.arg = arg;
	cb->write.cb_msg = msgfunc;
	cb->write.cb_part = NULL;
	cb->write.cb_error = errfunc;
	cb->write.cancelled = 0;

	if (events & ZMQ_POLLOUT) {
		if (cb->write.thread) {
			thread_cancel(cb->write.thread);
			cb->write.thread = NULL;
		}
		funcname_thread_add_event(master, frrzmq_write_msg, cbp, fd,
					  &cb->write.thread, funcname,
					  schedfrom, fromln);
	} else
		funcname_thread_add_read_write(
			THREAD_WRITE, master, frrzmq_write_msg, cbp, fd,
			&cb->write.thread, funcname, schedfrom, fromln);
	return 0;
}