/* 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); }
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; }
/* 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; }
/* 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); } }
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); }
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; }
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; }
/* 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; }
/* 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)); }
/* 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; }
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; }
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; }
/* 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; }
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; }
/* * 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 }
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); } }
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; }
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; }