kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
int index, int flags)
{
int ret;
int sock;
struct rtentry rtentry;
struct sockaddr_in sin_dest, sin_mask, sin_gate;
memset (&rtentry, 0, sizeof (struct rtentry));
memset (&sin_dest, 0, sizeof (struct sockaddr_in));
sin_dest.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin_dest.sin_len = sizeof (struct sockaddr_in);
#endif
sin_dest.sin_addr = dest->prefix;
if (gate)
{
memset (&sin_gate, 0, sizeof (struct sockaddr_in));
sin_gate.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin_gate.sin_len = sizeof (struct sockaddr_in);
#endif
sin_gate.sin_addr = *gate;
}
memset (&sin_mask, 0, sizeof (struct sockaddr_in));
sin_mask.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sin_gate.sin_len = sizeof (struct sockaddr_in);
#endif
masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
if (gate)
memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
#ifndef SUNOS_5
memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
#endif
if (dest->prefixlen == 32)
rtentry.rt_flags |= RTF_HOST;
if (gate && gate->s_addr != INADDR_ANY)
rtentry.rt_flags |= RTF_GATEWAY;
rtentry.rt_flags |= RTF_UP;
rtentry.rt_flags |= flags;
sock = socket (AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
zlog_warn ("can't make socket/n");
return -1;
}
ret = ioctl (sock, SIOCADDRT, &rtentry);
if (ret < 0)
{
switch (errno)
{
case EEXIST:
close (sock);
return ZEBRA_ERR_RTEXIST;
break;
case ENETUNREACH:
close (sock);
return ZEBRA_ERR_RTUNREACH;
break;
case EPERM:
close (sock);
return ZEBRA_ERR_EPERM;
break;
}
close (sock);
zlog_warn ("write : %s (%d)", strerror (errno), errno);
return 1;
}
close (sock);
return ret;
}