/* Interface function for the kernel routing table updates. Support for RTM_CHANGE will be needed. */ int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric) { int ret; caddr_t pnt; struct interface *ifp; struct sockaddr_in tmp_gate; #ifdef HAVE_IPV6 struct sockaddr_in6 tmp_gate6; #endif /* HAVE_IPV6 */ /* Sequencial number of routing message. */ static int msg_seq = 0; /* Struct of rt_msghdr and buffer for storing socket's data. */ struct { struct rt_msghdr rtm; char buf[512]; } msg; memset (&tmp_gate, 0, sizeof (struct sockaddr_in)); tmp_gate.sin_family = AF_INET; #ifdef HAVE_SIN_LEN tmp_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_SIN_LEN */ #ifdef HAVE_IPV6 memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6)); tmp_gate6.sin6_family = AF_INET6; #ifdef SIN6_LEN tmp_gate6.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ #endif /* HAVE_IPV6 */ if (routing_sock < 0) return ZEBRA_ERR_EPERM; /* Clear and set rt_msghdr values */ memset (&msg, 0, sizeof (struct rt_msghdr)); msg.rtm.rtm_version = RTM_VERSION; msg.rtm.rtm_type = message; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_flags = RTF_UP; msg.rtm.rtm_index = index; if (metric != 0) { msg.rtm.rtm_rmx.rmx_hopcount = metric; msg.rtm.rtm_inits |= RTV_HOPCOUNT; } ifp = if_lookup_by_index (index); if (gate && message == RTM_ADD) msg.rtm.rtm_flags |= RTF_GATEWAY; if (! gate && message == RTM_ADD && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; /* If no protocol specific gateway is specified, use link address for gateway. */ if (! gate) { if (!ifp) { zlog_warn ("no gateway found for interface index %d", index); return -1; } gate = (union sockunion *) & ifp->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); /* Additional flags. */ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; #ifdef HAVE_SIN_LEN #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP ((X)->sa.sa_len); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP (sizeof((X)->sa)); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #endif /* HAVE_SIN_LEN */ pnt = (caddr_t) msg.buf; /* Write each socket data into rtm message buffer */ SOCKADDRSET (dest, RTA_DST); SOCKADDRSET (gate, RTA_GATEWAY); SOCKADDRSET (mask, RTA_NETMASK); msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); if (ret != msg.rtm.rtm_msglen) { if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; zlog_warn ("write : %s (%d)", strerror (errno), errno); return -1; } return 0; }
/* Interface function for the kernel routing table updates. Support * for RTM_CHANGE will be needed. * Exported only for rt_socket.c */ int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric) { int ret; caddr_t pnt; struct interface *ifp; /* Sequencial number of routing message. */ static int msg_seq = 0; /* Struct of rt_msghdr and buffer for storing socket's data. */ struct { struct rt_msghdr rtm; char buf[512]; } msg; if (routing_sock < 0) return ZEBRA_ERR_EPERM; /* Clear and set rt_msghdr values */ memset (&msg, 0, sizeof (struct rt_msghdr)); msg.rtm.rtm_version = RTM_VERSION; msg.rtm.rtm_type = message; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_flags = RTF_UP; msg.rtm.rtm_index = index; if (metric != 0) { msg.rtm.rtm_rmx.rmx_hopcount = metric; msg.rtm.rtm_inits |= RTV_HOPCOUNT; } ifp = if_lookup_by_index (index); if (gate && message == RTM_ADD) msg.rtm.rtm_flags |= RTF_GATEWAY; /* When RTF_CLONING is unavailable on BSD, should we set some * other flag instead? */ #ifdef RTF_CLONING if (! gate && message == RTM_ADD && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; #endif /* RTF_CLONING */ /* If no protocol specific gateway is specified, use link address for gateway. */ if (! gate) { if (!ifp) { char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255"; if (dest) inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN); if (mask) inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN); zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d", __func__, dest_buf, mask_buf, index); return -1; } gate = (union sockunion *) & ifp->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); /* Additional flags. */ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; if (zebra_flags & ZEBRA_FLAG_REJECT) msg.rtm.rtm_flags |= RTF_REJECT; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP ((X)->sa.sa_len); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = SAROUNDUP (X); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ pnt = (caddr_t) msg.buf; /* Write each socket data into rtm message buffer */ SOCKADDRSET (dest, RTA_DST); SOCKADDRSET (gate, RTA_GATEWAY); SOCKADDRSET (mask, RTA_NETMASK); msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); if (ret != msg.rtm.rtm_msglen) { if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; if (errno == ESRCH) return ZEBRA_ERR_RTNOEXIST; zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno); return ZEBRA_ERR_KERNEL; } return ZEBRA_ERR_NOERROR; }