version 1.1.1.3, 2013/07/21 23:54:41
|
version 1.1.1.4, 2016/11/02 10:09:10
|
Line 20
|
Line 20
|
*/ |
*/ |
|
|
#include <zebra.h> |
#include <zebra.h> |
|
#include <net/if_arp.h> |
|
|
/* Hack for GNU libc version 2. */ |
/* Hack for GNU libc version 2. */ |
#ifndef MSG_TRUNC |
#ifndef MSG_TRUNC |
Line 36
|
Line 37
|
#include "rib.h" |
#include "rib.h" |
#include "thread.h" |
#include "thread.h" |
#include "privs.h" |
#include "privs.h" |
|
#include "vrf.h" |
|
|
#include "zebra/zserv.h" |
#include "zebra/zserv.h" |
#include "zebra/rt.h" |
#include "zebra/rt.h" |
Line 45
|
Line 47
|
|
|
#include "rt_netlink.h" |
#include "rt_netlink.h" |
|
|
/* Socket interface to kernel */ |
|
struct nlsock |
|
{ |
|
int sock; |
|
int seq; |
|
struct sockaddr_nl snl; |
|
const char *name; |
|
} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */ |
|
netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */ |
|
|
|
static const struct message nlmsg_str[] = { |
static const struct message nlmsg_str[] = { |
{RTM_NEWROUTE, "RTM_NEWROUTE"}, |
{RTM_NEWROUTE, "RTM_NEWROUTE"}, |
{RTM_DELROUTE, "RTM_DELROUTE"}, |
{RTM_DELROUTE, "RTM_DELROUTE"}, |
Line 77 extern u_int32_t nl_rcvbufsize;
|
Line 69 extern u_int32_t nl_rcvbufsize;
|
/* Note: on netlink systems, there should be a 1-to-1 mapping between interface |
/* Note: on netlink systems, there should be a 1-to-1 mapping between interface |
names and ifindex values. */ |
names and ifindex values. */ |
static void |
static void |
set_ifindex(struct interface *ifp, unsigned int ifi_index) | set_ifindex(struct interface *ifp, ifindex_t ifi_index) |
{ |
{ |
struct interface *oifp; |
struct interface *oifp; |
|
|
Line 101 set_ifindex(struct interface *ifp, unsigned int ifi_in
|
Line 93 set_ifindex(struct interface *ifp, unsigned int ifi_in
|
ifp->ifindex = ifi_index; |
ifp->ifindex = ifi_index; |
} |
} |
|
|
|
#ifndef SO_RCVBUFFORCE |
|
#define SO_RCVBUFFORCE (33) |
|
#endif |
|
|
static int |
static int |
netlink_recvbuf (struct nlsock *nl, uint32_t newsize) |
netlink_recvbuf (struct nlsock *nl, uint32_t newsize) |
{ |
{ |
Line 117 netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
|
Line 113 netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
|
return -1; |
return -1; |
} |
} |
|
|
ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize, | /* Try force option (linux >= 2.6.14) and fall back to normal set */ |
| if ( zserv_privs.change (ZPRIVS_RAISE) ) |
| zlog_err ("routing_socket: Can't raise privileges"); |
| ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize, |
sizeof(nl_rcvbufsize)); |
sizeof(nl_rcvbufsize)); |
|
if ( zserv_privs.change (ZPRIVS_LOWER) ) |
|
zlog_err ("routing_socket: Can't lower privileges"); |
if (ret < 0) |
if (ret < 0) |
|
ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize, |
|
sizeof(nl_rcvbufsize)); |
|
if (ret < 0) |
{ |
{ |
zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name, |
zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name, |
safe_strerror (errno)); |
safe_strerror (errno)); |
Line 142 netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
|
Line 146 netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
|
|
|
/* Make socket for Linux netlink interface. */ |
/* Make socket for Linux netlink interface. */ |
static int |
static int |
netlink_socket (struct nlsock *nl, unsigned long groups) | netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id) |
{ |
{ |
int ret; |
int ret; |
struct sockaddr_nl snl; |
struct sockaddr_nl snl; |
Line 150 netlink_socket (struct nlsock *nl, unsigned long group
|
Line 154 netlink_socket (struct nlsock *nl, unsigned long group
|
int namelen; |
int namelen; |
int save_errno; |
int save_errno; |
|
|
sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | if (zserv_privs.change (ZPRIVS_RAISE)) |
| { |
| zlog (NULL, LOG_ERR, "Can't raise privileges"); |
| return -1; |
| } |
| |
| sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id); |
if (sock < 0) |
if (sock < 0) |
{ |
{ |
zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name, |
zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name, |
Line 163 netlink_socket (struct nlsock *nl, unsigned long group
|
Line 173 netlink_socket (struct nlsock *nl, unsigned long group
|
snl.nl_groups = groups; |
snl.nl_groups = groups; |
|
|
/* Bind the socket to the netlink structure for anything. */ |
/* Bind the socket to the netlink structure for anything. */ |
if (zserv_privs.change (ZPRIVS_RAISE)) |
|
{ |
|
zlog (NULL, LOG_ERR, "Can't raise privileges"); |
|
return -1; |
|
} |
|
|
|
ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); |
ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); |
save_errno = errno; |
save_errno = errno; |
if (zserv_privs.change (ZPRIVS_LOWER)) |
if (zserv_privs.change (ZPRIVS_LOWER)) |
Line 260 netlink_request (int family, int type, struct nlsock *
|
Line 264 netlink_request (int family, int type, struct nlsock *
|
/* Receive message from netlink interface and pass those information |
/* Receive message from netlink interface and pass those information |
to the given function. */ |
to the given function. */ |
static int |
static int |
netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), | netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, |
struct nlsock *nl) | vrf_id_t), |
| struct nlsock *nl, struct zebra_vrf *zvrf) |
{ |
{ |
int status; |
int status; |
int ret = 0; |
int ret = 0; |
Line 270 netlink_parse_info (int (*filter) (struct sockaddr_nl
|
Line 275 netlink_parse_info (int (*filter) (struct sockaddr_nl
|
while (1) |
while (1) |
{ |
{ |
char buf[NL_PKT_BUF_SIZE]; |
char buf[NL_PKT_BUF_SIZE]; |
struct iovec iov = { buf, sizeof buf }; | struct iovec iov = { |
| .iov_base = buf, |
| .iov_len = sizeof buf |
| }; |
struct sockaddr_nl snl; |
struct sockaddr_nl snl; |
struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; | struct msghdr msg = { |
| .msg_name = (void *) &snl, |
| .msg_namelen = sizeof snl, |
| .msg_iov = &iov, |
| .msg_iovlen = 1 |
| }; |
struct nlmsghdr *h; |
struct nlmsghdr *h; |
|
|
status = recvmsg (nl->sock, &msg, 0); |
status = recvmsg (nl->sock, &msg, 0); |
Line 342 netlink_parse_info (int (*filter) (struct sockaddr_nl
|
Line 355 netlink_parse_info (int (*filter) (struct sockaddr_nl
|
} |
} |
|
|
/* Deal with errors that occur because of races in link handling */ |
/* Deal with errors that occur because of races in link handling */ |
if (nl == &netlink_cmd | if (nl == &zvrf->netlink_cmd |
&& ((msg_type == RTM_DELROUTE && |
&& ((msg_type == RTM_DELROUTE && |
(-errnum == ENODEV || -errnum == ESRCH)) |
(-errnum == ENODEV || -errnum == ESRCH)) |
|| (msg_type == RTM_NEWROUTE && -errnum == EEXIST))) |
|| (msg_type == RTM_NEWROUTE && -errnum == EEXIST))) |
Line 369 netlink_parse_info (int (*filter) (struct sockaddr_nl
|
Line 382 netlink_parse_info (int (*filter) (struct sockaddr_nl
|
lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, |
lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, |
h->nlmsg_seq, h->nlmsg_pid); |
h->nlmsg_seq, h->nlmsg_pid); |
|
|
/* skip unsolicited messages originating from command socket */ | /* skip unsolicited messages originating from command socket |
if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid) | * linux sets the originators port-id for {NEW|DEL}ADDR messages, |
| * so this has to be checked here. */ |
| if (nl != &zvrf->netlink_cmd |
| && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid |
| && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)) |
{ |
{ |
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
zlog_debug ("netlink_parse_info: %s packet comes from %s", |
zlog_debug ("netlink_parse_info: %s packet comes from %s", |
netlink_cmd.name, nl->name); | zvrf->netlink_cmd.name, nl->name); |
continue; |
continue; |
} |
} |
|
|
error = (*filter) (&snl, h); | error = (*filter) (&snl, h, zvrf->vrf_id); |
if (error < 0) |
if (error < 0) |
{ |
{ |
zlog (NULL, LOG_ERR, "%s filter function error", nl->name); |
zlog (NULL, LOG_ERR, "%s filter function error", nl->name); |
Line 446 netlink_interface_update_hw_addr (struct rtattr **tb,
|
Line 463 netlink_interface_update_hw_addr (struct rtattr **tb,
|
} |
} |
} |
} |
|
|
|
static enum zebra_link_type |
|
netlink_to_zebra_link_type (unsigned int hwt) |
|
{ |
|
switch (hwt) |
|
{ |
|
case ARPHRD_ETHER: return ZEBRA_LLT_ETHER; |
|
case ARPHRD_EETHER: return ZEBRA_LLT_EETHER; |
|
case ARPHRD_AX25: return ZEBRA_LLT_AX25; |
|
case ARPHRD_PRONET: return ZEBRA_LLT_PRONET; |
|
case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802; |
|
case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET; |
|
case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK; |
|
case ARPHRD_DLCI: return ZEBRA_LLT_DLCI; |
|
case ARPHRD_ATM: return ZEBRA_LLT_ATM; |
|
case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM; |
|
case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394; |
|
case ARPHRD_EUI64: return ZEBRA_LLT_EUI64; |
|
case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND; |
|
case ARPHRD_SLIP: return ZEBRA_LLT_SLIP; |
|
case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP; |
|
case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6; |
|
case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6; |
|
case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD; |
|
case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT; |
|
case ARPHRD_ROSE: return ZEBRA_LLT_ROSE; |
|
case ARPHRD_X25: return ZEBRA_LLT_X25; |
|
case ARPHRD_PPP: return ZEBRA_LLT_PPP; |
|
case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC; |
|
case ARPHRD_LAPB: return ZEBRA_LLT_LAPB; |
|
case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC; |
|
case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP; |
|
case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6; |
|
case ARPHRD_FRAD: return ZEBRA_LLT_FRAD; |
|
case ARPHRD_SKIP: return ZEBRA_LLT_SKIP; |
|
case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK; |
|
case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK; |
|
case ARPHRD_FDDI: return ZEBRA_LLT_FDDI; |
|
case ARPHRD_SIT: return ZEBRA_LLT_SIT; |
|
case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP; |
|
case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE; |
|
case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG; |
|
case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI; |
|
case ARPHRD_ECONET: return ZEBRA_LLT_ECONET; |
|
case ARPHRD_IRDA: return ZEBRA_LLT_IRDA; |
|
case ARPHRD_FCPP: return ZEBRA_LLT_FCPP; |
|
case ARPHRD_FCAL: return ZEBRA_LLT_FCAL; |
|
case ARPHRD_FCPL: return ZEBRA_LLT_FCPL; |
|
case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC; |
|
case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR; |
|
case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211; |
|
case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154; |
|
#ifdef ARPHRD_IP6GRE |
|
case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE; |
|
#endif |
|
#ifdef ARPHRD_IEEE802154_PHY |
|
case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY; |
|
#endif |
|
|
|
default: return ZEBRA_LLT_UNKNOWN; |
|
} |
|
} |
|
|
/* Called from interface_lookup_netlink(). This function is only used |
/* Called from interface_lookup_netlink(). This function is only used |
during bootstrap. */ |
during bootstrap. */ |
static int |
static int |
netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
int len; |
int len; |
struct ifinfomsg *ifi; |
struct ifinfomsg *ifi; |
Line 485 netlink_interface (struct sockaddr_nl *snl, struct nlm
|
Line 565 netlink_interface (struct sockaddr_nl *snl, struct nlm
|
name = (char *) RTA_DATA (tb[IFLA_IFNAME]); |
name = (char *) RTA_DATA (tb[IFLA_IFNAME]); |
|
|
/* Add interface. */ |
/* Add interface. */ |
ifp = if_get_by_name (name); | ifp = if_get_by_name_vrf (name, vrf_id); |
set_ifindex(ifp, ifi->ifi_index); |
set_ifindex(ifp, ifi->ifi_index); |
ifp->flags = ifi->ifi_flags & 0x0000fffff; |
ifp->flags = ifi->ifi_flags & 0x0000fffff; |
ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); |
ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); |
ifp->metric = 1; | ifp->metric = 0; |
|
|
/* Hardware type and address. */ |
/* Hardware type and address. */ |
ifp->hw_type = ifi->ifi_type; | ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type); |
netlink_interface_update_hw_addr (tb, ifp); |
netlink_interface_update_hw_addr (tb, ifp); |
|
|
if_add_update (ifp); |
if_add_update (ifp); |
Line 502 netlink_interface (struct sockaddr_nl *snl, struct nlm
|
Line 582 netlink_interface (struct sockaddr_nl *snl, struct nlm
|
|
|
/* Lookup interface IPv4/IPv6 address. */ |
/* Lookup interface IPv4/IPv6 address. */ |
static int |
static int |
netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
int len; |
int len; |
struct ifaddrmsg *ifa; |
struct ifaddrmsg *ifa; |
Line 532 netlink_interface_addr (struct sockaddr_nl *snl, struc
|
Line 613 netlink_interface_addr (struct sockaddr_nl *snl, struc
|
memset (tb, 0, sizeof tb); |
memset (tb, 0, sizeof tb); |
netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); |
netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); |
|
|
ifp = if_lookup_by_index (ifa->ifa_index); | ifp = if_lookup_by_index_vrf (ifa->ifa_index, vrf_id); |
if (ifp == NULL) |
if (ifp == NULL) |
{ |
{ |
zlog_err ("netlink_interface_addr can't find interface by index %d", | zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u", |
ifa->ifa_index); | ifa->ifa_index, vrf_id); |
return -1; |
return -1; |
} |
} |
|
|
if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ |
if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ |
{ |
{ |
char buf[BUFSIZ]; |
char buf[BUFSIZ]; |
zlog_debug ("netlink_interface_addr %s %s:", | zlog_debug ("netlink_interface_addr %s %s vrf %u:", |
lookup (nlmsg_str, h->nlmsg_type), ifp->name); | lookup (nlmsg_str, h->nlmsg_type), ifp->name, vrf_id); |
if (tb[IFA_LOCAL]) |
if (tb[IFA_LOCAL]) |
zlog_debug (" IFA_LOCAL %s/%d", |
zlog_debug (" IFA_LOCAL %s/%d", |
inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), |
inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), |
Line 637 netlink_interface_addr (struct sockaddr_nl *snl, struc
|
Line 718 netlink_interface_addr (struct sockaddr_nl *snl, struc
|
|
|
/* Looking up routing table by netlink interface. */ |
/* Looking up routing table by netlink interface. */ |
static int |
static int |
netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
int len; |
int len; |
struct rtmsg *rtm; |
struct rtmsg *rtm; |
Line 648 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 730 netlink_routing_table (struct sockaddr_nl *snl, struct
|
|
|
int index; |
int index; |
int table; |
int table; |
int metric; | u_int32_t mtu = 0; |
|
|
void *dest; |
void *dest; |
void *gate; |
void *gate; |
Line 689 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 771 netlink_routing_table (struct sockaddr_nl *snl, struct
|
flags |= ZEBRA_FLAG_SELFROUTE; |
flags |= ZEBRA_FLAG_SELFROUTE; |
|
|
index = 0; |
index = 0; |
metric = 0; |
|
dest = NULL; |
dest = NULL; |
gate = NULL; |
gate = NULL; |
src = NULL; |
src = NULL; |
Line 708 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 789 netlink_routing_table (struct sockaddr_nl *snl, struct
|
if (tb[RTA_GATEWAY]) |
if (tb[RTA_GATEWAY]) |
gate = RTA_DATA (tb[RTA_GATEWAY]); |
gate = RTA_DATA (tb[RTA_GATEWAY]); |
|
|
if (tb[RTA_PRIORITY]) | if (tb[RTA_METRICS]) |
metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); | { |
| struct rtattr *mxrta[RTAX_MAX+1]; |
|
|
|
memset (mxrta, 0, sizeof mxrta); |
|
netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), |
|
RTA_PAYLOAD(tb[RTA_METRICS])); |
|
|
|
if (mxrta[RTAX_MTU]) |
|
mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); |
|
} |
|
|
if (rtm->rtm_family == AF_INET) |
if (rtm->rtm_family == AF_INET) |
{ |
{ |
struct prefix_ipv4 p; |
struct prefix_ipv4 p; |
Line 720 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 810 netlink_routing_table (struct sockaddr_nl *snl, struct
|
|
|
if (!tb[RTA_MULTIPATH]) |
if (!tb[RTA_MULTIPATH]) |
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, |
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, |
table, metric, 0, SAFI_UNICAST); | vrf_id, table, 0, mtu, 0, SAFI_UNICAST); |
else |
else |
{ |
{ |
/* This is a multipath route */ |
/* This is a multipath route */ |
Line 735 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 825 netlink_routing_table (struct sockaddr_nl *snl, struct
|
rib->type = ZEBRA_ROUTE_KERNEL; |
rib->type = ZEBRA_ROUTE_KERNEL; |
rib->distance = 0; |
rib->distance = 0; |
rib->flags = flags; |
rib->flags = flags; |
rib->metric = metric; | rib->metric = 0; |
| rib->mtu = mtu; |
| rib->vrf_id = vrf_id; |
rib->table = table; |
rib->table = table; |
rib->nexthop_num = 0; |
rib->nexthop_num = 0; |
rib->uptime = time (NULL); |
rib->uptime = time (NULL); |
Line 745 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 837 netlink_routing_table (struct sockaddr_nl *snl, struct
|
if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) |
if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) |
break; |
break; |
|
|
rib->nexthop_num++; |
|
index = rtnh->rtnh_ifindex; |
index = rtnh->rtnh_ifindex; |
gate = 0; |
gate = 0; |
if (rtnh->rtnh_len > sizeof (*rtnh)) |
if (rtnh->rtnh_len > sizeof (*rtnh)) |
Line 785 netlink_routing_table (struct sockaddr_nl *snl, struct
|
Line 876 netlink_routing_table (struct sockaddr_nl *snl, struct
|
memcpy (&p.prefix, dest, 16); |
memcpy (&p.prefix, dest, 16); |
p.prefixlen = rtm->rtm_dst_len; |
p.prefixlen = rtm->rtm_dst_len; |
|
|
rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, | rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id, |
metric, 0, SAFI_UNICAST); | table, 0, mtu, 0, SAFI_UNICAST); |
} |
} |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
|
|
Line 810 static const struct message rtproto_str[] = {
|
Line 901 static const struct message rtproto_str[] = {
|
|
|
/* Routing information change from the kernel. */ |
/* Routing information change from the kernel. */ |
static int |
static int |
netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
int len; |
int len; |
struct rtmsg *rtm; |
struct rtmsg *rtm; |
Line 820 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 912 netlink_route_change (struct sockaddr_nl *snl, struct
|
|
|
int index; |
int index; |
int table; |
int table; |
int metric; | u_int32_t mtu = 0; |
|
|
void *dest; |
void *dest; |
void *gate; |
void *gate; |
Line 831 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 923 netlink_route_change (struct sockaddr_nl *snl, struct
|
if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) |
if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) |
{ |
{ |
/* If this is not route add/delete message print warning. */ |
/* If this is not route add/delete message print warning. */ |
zlog_warn ("Kernel message: %d\n", h->nlmsg_type); | zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id); |
return 0; |
return 0; |
} |
} |
|
|
/* Connected route. */ |
/* Connected route. */ |
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
zlog_debug ("%s %s %s proto %s", | zlog_debug ("%s %s %s proto %s vrf %u", |
h->nlmsg_type == |
h->nlmsg_type == |
RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", |
RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", |
rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", |
rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", |
rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", |
rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", |
lookup (rtproto_str, rtm->rtm_protocol)); | lookup (rtproto_str, rtm->rtm_protocol), |
| vrf_id); |
|
|
if (rtm->rtm_type != RTN_UNICAST) |
if (rtm->rtm_type != RTN_UNICAST) |
{ |
{ |
Line 874 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 967 netlink_route_change (struct sockaddr_nl *snl, struct
|
|
|
if (rtm->rtm_src_len != 0) |
if (rtm->rtm_src_len != 0) |
{ |
{ |
zlog_warn ("netlink_route_change(): no src len"); | zlog_warn ("netlink_route_change(): no src len, vrf %u", vrf_id); |
return 0; |
return 0; |
} |
} |
|
|
index = 0; |
index = 0; |
metric = 0; |
|
dest = NULL; |
dest = NULL; |
gate = NULL; |
gate = NULL; |
src = NULL; |
src = NULL; |
Line 898 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 990 netlink_route_change (struct sockaddr_nl *snl, struct
|
if (tb[RTA_PREFSRC]) |
if (tb[RTA_PREFSRC]) |
src = RTA_DATA (tb[RTA_PREFSRC]); |
src = RTA_DATA (tb[RTA_PREFSRC]); |
|
|
if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY]) | if (h->nlmsg_type == RTM_NEWROUTE) |
metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); | { |
| if (tb[RTA_METRICS]) |
| { |
| struct rtattr *mxrta[RTAX_MAX+1]; |
|
|
|
memset (mxrta, 0, sizeof mxrta); |
|
netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), |
|
RTA_PAYLOAD(tb[RTA_METRICS])); |
|
|
|
if (mxrta[RTAX_MTU]) |
|
mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); |
|
} |
|
} |
|
|
if (rtm->rtm_family == AF_INET) |
if (rtm->rtm_family == AF_INET) |
{ |
{ |
struct prefix_ipv4 p; |
struct prefix_ipv4 p; |
Line 910 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 1014 netlink_route_change (struct sockaddr_nl *snl, struct
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
{ |
{ |
if (h->nlmsg_type == RTM_NEWROUTE) | char buf[PREFIX_STRLEN]; |
zlog_debug ("RTM_NEWROUTE %s/%d", | zlog_debug ("%s %s vrf %u", |
inet_ntoa (p.prefix), p.prefixlen); | h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", |
else | prefix2str (&p, buf, sizeof(buf)), vrf_id); |
zlog_debug ("RTM_DELROUTE %s/%d", | |
inet_ntoa (p.prefix), p.prefixlen); | |
} |
} |
|
|
if (h->nlmsg_type == RTM_NEWROUTE) |
if (h->nlmsg_type == RTM_NEWROUTE) |
{ |
{ |
if (!tb[RTA_MULTIPATH]) |
if (!tb[RTA_MULTIPATH]) |
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, | rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id, |
metric, 0, SAFI_UNICAST); | table, 0, mtu, 0, SAFI_UNICAST); |
else |
else |
{ |
{ |
/* This is a multipath route */ |
/* This is a multipath route */ |
Line 937 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 1039 netlink_route_change (struct sockaddr_nl *snl, struct
|
rib->type = ZEBRA_ROUTE_KERNEL; |
rib->type = ZEBRA_ROUTE_KERNEL; |
rib->distance = 0; |
rib->distance = 0; |
rib->flags = 0; |
rib->flags = 0; |
rib->metric = metric; | rib->metric = 0; |
| rib->mtu = mtu; |
| rib->vrf_id = vrf_id; |
rib->table = table; |
rib->table = table; |
rib->nexthop_num = 0; |
rib->nexthop_num = 0; |
rib->uptime = time (NULL); |
rib->uptime = time (NULL); |
Line 947 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 1051 netlink_route_change (struct sockaddr_nl *snl, struct
|
if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) |
if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) |
break; |
break; |
|
|
rib->nexthop_num++; |
|
index = rtnh->rtnh_ifindex; |
index = rtnh->rtnh_ifindex; |
gate = 0; |
gate = 0; |
if (rtnh->rtnh_len > sizeof (*rtnh)) |
if (rtnh->rtnh_len > sizeof (*rtnh)) |
Line 980 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 1083 netlink_route_change (struct sockaddr_nl *snl, struct
|
} |
} |
} |
} |
else |
else |
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); | rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, |
| SAFI_UNICAST); |
} |
} |
|
|
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
if (rtm->rtm_family == AF_INET6) |
if (rtm->rtm_family == AF_INET6) |
{ |
{ |
struct prefix_ipv6 p; |
struct prefix_ipv6 p; |
char buf[BUFSIZ]; |
|
|
|
p.family = AF_INET6; |
p.family = AF_INET6; |
memcpy (&p.prefix, dest, 16); |
memcpy (&p.prefix, dest, 16); |
Line 995 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 1098 netlink_route_change (struct sockaddr_nl *snl, struct
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
{ |
{ |
if (h->nlmsg_type == RTM_NEWROUTE) | char buf[PREFIX_STRLEN]; |
zlog_debug ("RTM_NEWROUTE %s/%d", | zlog_debug ("%s %s vrf %u", |
inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), | h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", |
p.prefixlen); | prefix2str (&p, buf, sizeof(buf)), vrf_id); |
else | |
zlog_debug ("RTM_DELROUTE %s/%d", | |
inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), | |
p.prefixlen); | |
} |
} |
|
|
if (h->nlmsg_type == RTM_NEWROUTE) |
if (h->nlmsg_type == RTM_NEWROUTE) |
rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST); | rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, |
| 0, mtu, 0, SAFI_UNICAST); |
else |
else |
rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); | rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, |
| SAFI_UNICAST); |
} |
} |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
|
|
Line 1016 netlink_route_change (struct sockaddr_nl *snl, struct
|
Line 1117 netlink_route_change (struct sockaddr_nl *snl, struct
|
} |
} |
|
|
static int |
static int |
netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
int len; |
int len; |
struct ifinfomsg *ifi; |
struct ifinfomsg *ifi; |
Line 1029 netlink_link_change (struct sockaddr_nl *snl, struct n
|
Line 1131 netlink_link_change (struct sockaddr_nl *snl, struct n
|
if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) |
if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) |
{ |
{ |
/* If this is not link add/delete message so print warning. */ |
/* If this is not link add/delete message so print warning. */ |
zlog_warn ("netlink_link_change: wrong kernel message %d\n", | zlog_warn ("netlink_link_change: wrong kernel message %d vrf %u\n", |
h->nlmsg_type); | h->nlmsg_type, vrf_id); |
return 0; |
return 0; |
} |
} |
|
|
Line 1047 netlink_link_change (struct sockaddr_nl *snl, struct n
|
Line 1149 netlink_link_change (struct sockaddr_nl *snl, struct n
|
if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) |
if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) |
{ |
{ |
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); | zlog_debug ("%s: ignoring IFLA_WIRELESS message, vrf %u", __func__, |
| vrf_id); |
return 0; |
return 0; |
} |
} |
#endif /* IFLA_WIRELESS */ |
#endif /* IFLA_WIRELESS */ |
Line 1059 netlink_link_change (struct sockaddr_nl *snl, struct n
|
Line 1162 netlink_link_change (struct sockaddr_nl *snl, struct n
|
/* Add interface. */ |
/* Add interface. */ |
if (h->nlmsg_type == RTM_NEWLINK) |
if (h->nlmsg_type == RTM_NEWLINK) |
{ |
{ |
ifp = if_lookup_by_name (name); | ifp = if_lookup_by_name_vrf (name, vrf_id); |
|
|
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) |
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) |
{ |
{ |
if (ifp == NULL) |
if (ifp == NULL) |
ifp = if_get_by_name (name); | ifp = if_get_by_name_vrf (name, vrf_id); |
|
|
set_ifindex(ifp, ifi->ifi_index); |
set_ifindex(ifp, ifi->ifi_index); |
ifp->flags = ifi->ifi_flags & 0x0000fffff; |
ifp->flags = ifi->ifi_flags & 0x0000fffff; |
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); |
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); |
ifp->metric = 1; | ifp->metric = 0; |
|
|
netlink_interface_update_hw_addr (tb, ifp); |
netlink_interface_update_hw_addr (tb, ifp); |
|
|
Line 1081 netlink_link_change (struct sockaddr_nl *snl, struct n
|
Line 1184 netlink_link_change (struct sockaddr_nl *snl, struct n
|
/* Interface status change. */ |
/* Interface status change. */ |
set_ifindex(ifp, ifi->ifi_index); |
set_ifindex(ifp, ifi->ifi_index); |
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); |
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); |
ifp->metric = 1; | ifp->metric = 0; |
|
|
netlink_interface_update_hw_addr (tb, ifp); |
netlink_interface_update_hw_addr (tb, ifp); |
|
|
Line 1105 netlink_link_change (struct sockaddr_nl *snl, struct n
|
Line 1208 netlink_link_change (struct sockaddr_nl *snl, struct n
|
else |
else |
{ |
{ |
/* RTM_DELLINK. */ |
/* RTM_DELLINK. */ |
ifp = if_lookup_by_name (name); | ifp = if_lookup_by_name_vrf (name, vrf_id); |
|
|
if (ifp == NULL) |
if (ifp == NULL) |
{ |
{ |
zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", | zlog_warn ("interface %s vrf %u is deleted but can't find", |
name); | name, vrf_id); |
return 0; |
return 0; |
} |
} |
|
|
Line 1121 netlink_link_change (struct sockaddr_nl *snl, struct n
|
Line 1224 netlink_link_change (struct sockaddr_nl *snl, struct n
|
} |
} |
|
|
static int |
static int |
netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
/* JF: Ignore messages that aren't from the kernel */ |
/* JF: Ignore messages that aren't from the kernel */ |
if ( snl->nl_pid != 0 ) |
if ( snl->nl_pid != 0 ) |
Line 1133 netlink_information_fetch (struct sockaddr_nl *snl, st
|
Line 1237 netlink_information_fetch (struct sockaddr_nl *snl, st
|
switch (h->nlmsg_type) |
switch (h->nlmsg_type) |
{ |
{ |
case RTM_NEWROUTE: |
case RTM_NEWROUTE: |
return netlink_route_change (snl, h); | return netlink_route_change (snl, h, vrf_id); |
break; |
break; |
case RTM_DELROUTE: |
case RTM_DELROUTE: |
return netlink_route_change (snl, h); | return netlink_route_change (snl, h, vrf_id); |
break; |
break; |
case RTM_NEWLINK: |
case RTM_NEWLINK: |
return netlink_link_change (snl, h); | return netlink_link_change (snl, h, vrf_id); |
break; |
break; |
case RTM_DELLINK: |
case RTM_DELLINK: |
return netlink_link_change (snl, h); | return netlink_link_change (snl, h, vrf_id); |
break; |
break; |
case RTM_NEWADDR: |
case RTM_NEWADDR: |
return netlink_interface_addr (snl, h); | return netlink_interface_addr (snl, h, vrf_id); |
break; |
break; |
case RTM_DELADDR: |
case RTM_DELADDR: |
return netlink_interface_addr (snl, h); | return netlink_interface_addr (snl, h, vrf_id); |
break; |
break; |
default: |
default: |
zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type); | zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type, |
| vrf_id); |
break; |
break; |
} |
} |
return 0; |
return 0; |
Line 1159 netlink_information_fetch (struct sockaddr_nl *snl, st
|
Line 1264 netlink_information_fetch (struct sockaddr_nl *snl, st
|
|
|
/* Interface lookup by netlink socket. */ |
/* Interface lookup by netlink socket. */ |
int |
int |
interface_lookup_netlink (void) | interface_lookup_netlink (struct zebra_vrf *zvrf) |
{ |
{ |
int ret; |
int ret; |
|
|
/* Get interface information. */ |
/* Get interface information. */ |
ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); | ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
ret = netlink_parse_info (netlink_interface, &netlink_cmd); | ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
|
|
/* Get IPv4 address of the interfaces. */ |
/* Get IPv4 address of the interfaces. */ |
ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd); | ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); | ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
|
|
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
/* Get IPv6 address of the interfaces. */ |
/* Get IPv6 address of the interfaces. */ |
ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd); | ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); | ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
Line 1195 interface_lookup_netlink (void)
|
Line 1300 interface_lookup_netlink (void)
|
/* Routing table read function using netlink interface. Only called |
/* Routing table read function using netlink interface. Only called |
bootstrap time. */ |
bootstrap time. */ |
int |
int |
netlink_route_read (void) | netlink_route_read (struct zebra_vrf *zvrf) |
{ |
{ |
int ret; |
int ret; |
|
|
/* Get IPv4 routing table. */ |
/* Get IPv4 routing table. */ |
ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); | ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); | ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
|
|
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
/* Get IPv6 routing table. */ |
/* Get IPv6 routing table. */ |
ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd); | ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); | ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf); |
if (ret < 0) |
if (ret < 0) |
return ret; |
return ret; |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
Line 1223 netlink_route_read (void)
|
Line 1328 netlink_route_read (void)
|
/* Utility function comes from iproute2. |
/* Utility function comes from iproute2. |
Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */ |
Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */ |
int |
int |
addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) | addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen) |
{ |
{ |
int len; | size_t len; |
struct rtattr *rta; |
struct rtattr *rta; |
|
|
len = RTA_LENGTH (alen); |
len = RTA_LENGTH (alen); |
Line 1265 rta_addattr_l (struct rtattr *rta, int maxlen, int typ
|
Line 1370 rta_addattr_l (struct rtattr *rta, int maxlen, int typ
|
/* Utility function comes from iproute2. |
/* Utility function comes from iproute2. |
Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */ |
Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */ |
int |
int |
addattr32 (struct nlmsghdr *n, int maxlen, int type, int data) | addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data) |
{ |
{ |
int len; | size_t len; |
struct rtattr *rta; |
struct rtattr *rta; |
|
|
len = RTA_LENGTH (4); |
len = RTA_LENGTH (4); |
Line 1285 addattr32 (struct nlmsghdr *n, int maxlen, int type, i
|
Line 1390 addattr32 (struct nlmsghdr *n, int maxlen, int type, i
|
} |
} |
|
|
static int |
static int |
netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) | netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h, |
| vrf_id_t vrf_id) |
{ |
{ |
zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); | zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type, |
| vrf_id); |
return 0; |
return 0; |
} |
} |
|
|
/* sendmsg() to netlink socket then recvmsg(). */ |
/* sendmsg() to netlink socket then recvmsg(). */ |
static int |
static int |
netlink_talk (struct nlmsghdr *n, struct nlsock *nl) | netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf) |
{ |
{ |
int status; |
int status; |
struct sockaddr_nl snl; |
struct sockaddr_nl snl; |
struct iovec iov = { (void *) n, n->nlmsg_len }; | struct iovec iov = { |
struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; | .iov_base = (void *) n, |
| .iov_len = n->nlmsg_len |
| }; |
| struct msghdr msg = { |
| .msg_name = (void *) &snl, |
| .msg_namelen = sizeof snl, |
| .msg_iov = &iov, |
| .msg_iovlen = 1, |
| }; |
int save_errno; |
int save_errno; |
|
|
memset (&snl, 0, sizeof snl); |
memset (&snl, 0, sizeof snl); |
Line 1334 netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
|
Line 1449 netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
|
* Get reply from netlink socket. |
* Get reply from netlink socket. |
* The reply should either be an acknowlegement or an error. |
* The reply should either be an acknowlegement or an error. |
*/ |
*/ |
return netlink_parse_info (netlink_talk_filter, nl); | return netlink_parse_info (netlink_talk_filter, nl, zvrf); |
} |
} |
|
|
/* Routing table change via netlink interface. */ | /* This function takes a nexthop as argument and adds |
static int | * the appropriate netlink attributes to an existing |
netlink_route (int cmd, int family, void *dest, int length, void *gate, | * netlink message. |
int index, int zebra_flags, int table) | * |
| * @param routedesc: Human readable description of route type |
| * (direct/recursive, single-/multipath) |
| * @param bytelen: Length of addresses in bytes. |
| * @param nexthop: Nexthop information |
| * @param nlmsg: nlmsghdr structure to fill in. |
| * @param req_size: The size allocated for the message. |
| */ |
| static void |
| _netlink_route_build_singlepath( |
| const char *routedesc, |
| int bytelen, |
| struct nexthop *nexthop, |
| struct nlmsghdr *nlmsg, |
| struct rtmsg *rtmsg, |
| size_t req_size) |
{ |
{ |
int ret; | if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) |
int bytelen; | rtmsg->rtm_flags |= RTNH_F_ONLINK; |
struct sockaddr_nl snl; | if (nexthop->type == NEXTHOP_TYPE_IPV4 |
int discard; | || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) |
| { |
| addattr_l (nlmsg, req_size, RTA_GATEWAY, |
| &nexthop->gate.ipv4, bytelen); |
| if (nexthop->src.ipv4.s_addr) |
| addattr_l (nlmsg, req_size, RTA_PREFSRC, |
| &nexthop->src.ipv4, bytelen); |
|
|
struct | if (IS_ZEBRA_DEBUG_KERNEL) |
{ | zlog_debug("netlink_route_multipath() (%s): " |
struct nlmsghdr n; | "nexthop via %s if %u", |
struct rtmsg r; | routedesc, |
char buf[NL_PKT_BUF_SIZE]; | inet_ntoa (nexthop->gate.ipv4), |
} req; | nexthop->ifindex); |
| } |
| #ifdef HAVE_IPV6 |
| if (nexthop->type == NEXTHOP_TYPE_IPV6 |
| || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME |
| || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) |
| { |
| addattr_l (nlmsg, req_size, RTA_GATEWAY, |
| &nexthop->gate.ipv6, bytelen); |
|
|
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); | if (IS_ZEBRA_DEBUG_KERNEL) |
| zlog_debug("netlink_route_multipath() (%s): " |
| "nexthop via %s if %u", |
| routedesc, |
| inet6_ntoa (nexthop->gate.ipv6), |
| nexthop->ifindex); |
| } |
| #endif /* HAVE_IPV6 */ |
| if (nexthop->type == NEXTHOP_TYPE_IFINDEX |
| || nexthop->type == NEXTHOP_TYPE_IFNAME |
| || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) |
| { |
| addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); |
|
|
bytelen = (family == AF_INET ? 4 : 16); | if (nexthop->src.ipv4.s_addr) |
| addattr_l (nlmsg, req_size, RTA_PREFSRC, |
| &nexthop->src.ipv4, bytelen); |
|
|
req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); | if (IS_ZEBRA_DEBUG_KERNEL) |
req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; | zlog_debug("netlink_route_multipath() (%s): " |
req.n.nlmsg_type = cmd; | "nexthop via if %u", routedesc, nexthop->ifindex); |
req.r.rtm_family = family; | } |
req.r.rtm_table = table; | |
req.r.rtm_dst_len = length; | |
req.r.rtm_protocol = RTPROT_ZEBRA; | |
req.r.rtm_scope = RT_SCOPE_UNIVERSE; | |
|
|
if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE) | if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX |
|| (zebra_flags & ZEBRA_FLAG_REJECT)) | || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) |
discard = 1; | |
else | |
discard = 0; | |
| |
if (cmd == RTM_NEWROUTE) | |
{ |
{ |
if (discard) | addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); |
{ | |
if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) | if (IS_ZEBRA_DEBUG_KERNEL) |
req.r.rtm_type = RTN_BLACKHOLE; | zlog_debug("netlink_route_multipath() (%s): " |
else if (zebra_flags & ZEBRA_FLAG_REJECT) | "nexthop via if %u", routedesc, nexthop->ifindex); |
req.r.rtm_type = RTN_UNREACHABLE; | |
else | |
assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ | |
} | |
else | |
req.r.rtm_type = RTN_UNICAST; | |
} |
} |
|
} |
|
|
if (dest) | /* This function takes a nexthop as argument and |
addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); | * appends to the given rtattr/rtnexthop pair the |
| * representation of the nexthop. If the nexthop |
| * defines a preferred source, the src parameter |
| * will be modified to point to that src, otherwise |
| * it will be kept unmodified. |
| * |
| * @param routedesc: Human readable description of route type |
| * (direct/recursive, single-/multipath) |
| * @param bytelen: Length of addresses in bytes. |
| * @param nexthop: Nexthop information |
| * @param rta: rtnetlink attribute structure |
| * @param rtnh: pointer to an rtnetlink nexthop structure |
| * @param src: pointer pointing to a location where |
| * the prefsrc should be stored. |
| */ |
| static void |
| _netlink_route_build_multipath( |
| const char *routedesc, |
| int bytelen, |
| struct nexthop *nexthop, |
| struct rtattr *rta, |
| struct rtnexthop *rtnh, |
| union g_addr **src |
| ) |
| { |
| rtnh->rtnh_len = sizeof (*rtnh); |
| rtnh->rtnh_flags = 0; |
| rtnh->rtnh_hops = 0; |
| rta->rta_len += rtnh->rtnh_len; |
|
|
if (!discard) | if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) |
| rtnh->rtnh_flags |= RTNH_F_ONLINK; |
| |
| if (nexthop->type == NEXTHOP_TYPE_IPV4 |
| || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) |
{ |
{ |
if (gate) | rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, |
addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen); | &nexthop->gate.ipv4, bytelen); |
if (index > 0) | rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; |
addattr32 (&req.n, sizeof req, RTA_OIF, index); | |
| if (nexthop->src.ipv4.s_addr) |
| *src = &nexthop->src; |
| |
| if (IS_ZEBRA_DEBUG_KERNEL) |
| zlog_debug("netlink_route_multipath() (%s): " |
| "nexthop via %s if %u", |
| routedesc, |
| inet_ntoa (nexthop->gate.ipv4), |
| nexthop->ifindex); |
} |
} |
|
#ifdef HAVE_IPV6 |
|
if (nexthop->type == NEXTHOP_TYPE_IPV6 |
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME |
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) |
|
{ |
|
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, |
|
&nexthop->gate.ipv6, bytelen); |
|
rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; |
|
|
/* Destination netlink address. */ | if (IS_ZEBRA_DEBUG_KERNEL) |
memset (&snl, 0, sizeof snl); | zlog_debug("netlink_route_multipath() (%s): " |
snl.nl_family = AF_NETLINK; | "nexthop via %s if %u", |
| routedesc, |
| inet6_ntoa (nexthop->gate.ipv6), |
| nexthop->ifindex); |
| } |
| #endif /* HAVE_IPV6 */ |
| /* ifindex */ |
| if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX |
| || nexthop->type == NEXTHOP_TYPE_IFINDEX |
| || nexthop->type == NEXTHOP_TYPE_IFNAME) |
| { |
| rtnh->rtnh_ifindex = nexthop->ifindex; |
| if (nexthop->src.ipv4.s_addr) |
| *src = &nexthop->src; |
| if (IS_ZEBRA_DEBUG_KERNEL) |
| zlog_debug("netlink_route_multipath() (%s): " |
| "nexthop via if %u", routedesc, nexthop->ifindex); |
| } |
| else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME |
| || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) |
| { |
| rtnh->rtnh_ifindex = nexthop->ifindex; |
|
|
/* Talk to netlink socket. */ | if (IS_ZEBRA_DEBUG_KERNEL) |
ret = netlink_talk (&req.n, &netlink_cmd); | zlog_debug("netlink_route_multipath() (%s): " |
if (ret < 0) | "nexthop via if %u", routedesc, nexthop->ifindex); |
return -1; | } |
| else |
| { |
| rtnh->rtnh_ifindex = 0; |
| } |
| } |
|
|
return 0; | /* Log debug information for netlink_route_multipath |
| * if debug logging is enabled. |
| * |
| * @param cmd: Netlink command which is to be processed |
| * @param p: Prefix for which the change is due |
| * @param nexthop: Nexthop which is currently processed |
| * @param routedesc: Semantic annotation for nexthop |
| * (recursive, multipath, etc.) |
| * @param family: Address family which the change concerns |
| */ |
| static void |
| _netlink_route_debug( |
| int cmd, |
| struct prefix *p, |
| struct nexthop *nexthop, |
| const char *routedesc, |
| int family, |
| struct zebra_vrf *zvrf) |
| { |
| if (IS_ZEBRA_DEBUG_KERNEL) |
| { |
| char buf[PREFIX_STRLEN]; |
| zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s", |
| routedesc, |
| lookup (nlmsg_str, cmd), |
| prefix2str (p, buf, sizeof(buf)), |
| zvrf->vrf_id, |
| nexthop_type_to_str (nexthop->type)); |
| } |
} |
} |
|
|
/* Routing table change via netlink interface. */ |
/* Routing table change via netlink interface. */ |
static int |
static int |
netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, | netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) |
int family) | |
{ |
{ |
int bytelen; |
int bytelen; |
struct sockaddr_nl snl; |
struct sockaddr_nl snl; |
struct nexthop *nexthop = NULL; | struct nexthop *nexthop = NULL, *tnexthop; |
int nexthop_num = 0; | int recursing; |
| int nexthop_num; |
int discard; |
int discard; |
|
int family = PREFIX_FAMILY(p); |
|
const char *routedesc; |
|
|
struct |
struct |
{ |
{ |
Line 1429 netlink_route_multipath (int cmd, struct prefix *p, st
|
Line 1678 netlink_route_multipath (int cmd, struct prefix *p, st
|
char buf[NL_PKT_BUF_SIZE]; |
char buf[NL_PKT_BUF_SIZE]; |
} req; |
} req; |
|
|
|
struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id); |
|
|
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); |
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); |
|
|
bytelen = (family == AF_INET ? 4 : 16); |
bytelen = (family == AF_INET ? 4 : 16); |
|
|
req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); |
req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); |
req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; | req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST; |
req.n.nlmsg_type = cmd; |
req.n.nlmsg_type = cmd; |
req.r.rtm_family = family; |
req.r.rtm_family = family; |
req.r.rtm_table = rib->table; |
req.r.rtm_table = rib->table; |
req.r.rtm_dst_len = p->prefixlen; |
req.r.rtm_dst_len = p->prefixlen; |
req.r.rtm_protocol = RTPROT_ZEBRA; |
req.r.rtm_protocol = RTPROT_ZEBRA; |
req.r.rtm_scope = RT_SCOPE_UNIVERSE; | req.r.rtm_scope = RT_SCOPE_LINK; |
|
|
if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) |
if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) |
discard = 1; |
discard = 1; |
Line 1465 netlink_route_multipath (int cmd, struct prefix *p, st
|
Line 1716 netlink_route_multipath (int cmd, struct prefix *p, st
|
addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); |
addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); |
|
|
/* Metric. */ |
/* Metric. */ |
addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric); | addattr32 (&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); |
|
|
|
if (rib->mtu || rib->nexthop_mtu) |
|
{ |
|
char buf[NL_PKT_BUF_SIZE]; |
|
struct rtattr *rta = (void *) buf; |
|
u_int32_t mtu = rib->mtu; |
|
if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu)) |
|
mtu = rib->nexthop_mtu; |
|
rta->rta_type = RTA_METRICS; |
|
rta->rta_len = RTA_LENGTH(0); |
|
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu); |
|
addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta), |
|
RTA_PAYLOAD (rta)); |
|
} |
|
|
if (discard) |
if (discard) |
{ |
{ |
if (cmd == RTM_NEWROUTE) |
if (cmd == RTM_NEWROUTE) |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) | for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); | { |
| /* We shouldn't encounter recursive nexthops on discard routes, |
| * but it is probably better to handle that case correctly anyway. |
| */ |
| if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
| continue; |
| SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
| } |
goto skip; |
goto skip; |
} |
} |
|
|
/* Multipath case. */ | /* Count overall nexthops so we can decide whether to use singlepath |
if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) | * or multipath case. */ |
| nexthop_num = 0; |
| for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
{ |
{ |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) | if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
| continue; |
| if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
| continue; |
| if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
| continue; |
| |
| if (nexthop->type != NEXTHOP_TYPE_IFINDEX && |
| nexthop->type != NEXTHOP_TYPE_IFNAME) |
| req.r.rtm_scope = RT_SCOPE_UNIVERSE; |
| |
| nexthop_num++; |
| } |
| |
| /* Singlepath case. */ |
| if (nexthop_num == 1 || MULTIPATH_NUM == 1) |
| { |
| nexthop_num = 0; |
| for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
{ |
{ |
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
|
continue; |
|
|
if ((cmd == RTM_NEWROUTE |
if ((cmd == RTM_NEWROUTE |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
|| (cmd == RTM_DELROUTE |
|| (cmd == RTM_DELROUTE |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) |
{ |
{ |
|
routedesc = recursing ? "recursive, 1 hop" : "single hop"; |
|
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) | _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); |
{ | _netlink_route_build_singlepath(routedesc, bytelen, |
if (IS_ZEBRA_DEBUG_KERNEL) | nexthop, &req.n, &req.r, |
{ | sizeof req); |
zlog_debug | |
("netlink_route_multipath() (recursive, 1 hop): " | |
"%s %s/%d, type %s", lookup (nlmsg_str, cmd), | |
#ifdef HAVE_IPV6 | |
(family == AF_INET) ? inet_ntoa (p->u.prefix4) : | |
inet6_ntoa (p->u.prefix6), | |
#else | |
inet_ntoa (p->u.prefix4), | |
#endif /* HAVE_IPV6 */ | |
| |
p->prefixlen, nexthop_type_to_str (nexthop->rtype)); | |
} | |
|
|
if (nexthop->rtype == NEXTHOP_TYPE_IPV4 |
|
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) |
|
{ |
|
addattr_l (&req.n, sizeof req, RTA_GATEWAY, |
|
&nexthop->rgate.ipv4, bytelen); |
|
if (nexthop->src.ipv4.s_addr) |
|
addattr_l(&req.n, sizeof req, RTA_PREFSRC, |
|
&nexthop->src.ipv4, bytelen); |
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (recursive, " |
|
"1 hop): nexthop via %s if %u", |
|
inet_ntoa (nexthop->rgate.ipv4), |
|
nexthop->rifindex); |
|
} |
|
#ifdef HAVE_IPV6 |
|
if (nexthop->rtype == NEXTHOP_TYPE_IPV6 |
|
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX |
|
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) |
|
{ |
|
addattr_l (&req.n, sizeof req, RTA_GATEWAY, |
|
&nexthop->rgate.ipv6, bytelen); |
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (recursive, " |
|
"1 hop): nexthop via %s if %u", |
|
inet6_ntoa (nexthop->rgate.ipv6), |
|
nexthop->rifindex); |
|
} |
|
#endif /* HAVE_IPV6 */ |
|
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX |
|
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME |
|
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX |
|
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX |
|
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) |
|
{ |
|
addattr32 (&req.n, sizeof req, RTA_OIF, |
|
nexthop->rifindex); |
|
if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX |
|
|| nexthop->rtype == NEXTHOP_TYPE_IFINDEX) |
|
&& nexthop->src.ipv4.s_addr) |
|
addattr_l (&req.n, sizeof req, RTA_PREFSRC, |
|
&nexthop->src.ipv4, bytelen); |
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (recursive, " |
|
"1 hop): nexthop via if %u", |
|
nexthop->rifindex); |
|
} |
|
} |
|
else |
|
{ |
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
{ |
|
zlog_debug |
|
("netlink_route_multipath() (single hop): " |
|
"%s %s/%d, type %s", lookup (nlmsg_str, cmd), |
|
#ifdef HAVE_IPV6 |
|
(family == AF_INET) ? inet_ntoa (p->u.prefix4) : |
|
inet6_ntoa (p->u.prefix6), |
|
#else |
|
inet_ntoa (p->u.prefix4), |
|
#endif /* HAVE_IPV6 */ |
|
p->prefixlen, nexthop_type_to_str (nexthop->type)); |
|
} |
|
|
|
if (nexthop->type == NEXTHOP_TYPE_IPV4 |
|
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) |
|
{ |
|
addattr_l (&req.n, sizeof req, RTA_GATEWAY, |
|
&nexthop->gate.ipv4, bytelen); |
|
if (nexthop->src.ipv4.s_addr) |
|
addattr_l (&req.n, sizeof req, RTA_PREFSRC, |
|
&nexthop->src.ipv4, bytelen); |
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (single hop): " |
|
"nexthop via %s if %u", |
|
inet_ntoa (nexthop->gate.ipv4), |
|
nexthop->ifindex); |
|
} |
|
#ifdef HAVE_IPV6 |
|
if (nexthop->type == NEXTHOP_TYPE_IPV6 |
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME |
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) |
|
{ |
|
addattr_l (&req.n, sizeof req, RTA_GATEWAY, |
|
&nexthop->gate.ipv6, bytelen); |
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (single hop): " |
|
"nexthop via %s if %u", |
|
inet6_ntoa (nexthop->gate.ipv6), |
|
nexthop->ifindex); |
|
} |
|
#endif /* HAVE_IPV6 */ |
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX |
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME |
|
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) |
|
{ |
|
addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex); |
|
|
|
if (nexthop->src.ipv4.s_addr) |
|
addattr_l (&req.n, sizeof req, RTA_PREFSRC, |
|
&nexthop->src.ipv4, bytelen); |
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (single hop): " |
|
"nexthop via if %u", nexthop->ifindex); |
|
} |
|
else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX |
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) |
|
{ |
|
addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex); |
|
|
|
if (IS_ZEBRA_DEBUG_KERNEL) |
|
zlog_debug("netlink_route_multipath() (single hop): " |
|
"nexthop via if %u", nexthop->ifindex); |
|
} |
|
} |
|
|
|
if (cmd == RTM_NEWROUTE) |
if (cmd == RTM_NEWROUTE) |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
|
|
Line 1644 netlink_route_multipath (int cmd, struct prefix *p, st
|
Line 1807 netlink_route_multipath (int cmd, struct prefix *p, st
|
rtnh = RTA_DATA (rta); |
rtnh = RTA_DATA (rta); |
|
|
nexthop_num = 0; |
nexthop_num = 0; |
for (nexthop = rib->nexthop; | for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM); | |
nexthop = nexthop->next) | |
{ |
{ |
|
if (nexthop_num >= MULTIPATH_NUM) |
|
break; |
|
|
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
|
continue; |
|
|
if ((cmd == RTM_NEWROUTE |
if ((cmd == RTM_NEWROUTE |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
|| (cmd == RTM_DELROUTE |
|| (cmd == RTM_DELROUTE |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) |
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) |
{ |
{ |
|
routedesc = recursing ? "recursive, multihop" : "multihop"; |
nexthop_num++; |
nexthop_num++; |
|
|
rtnh->rtnh_len = sizeof (*rtnh); | _netlink_route_debug(cmd, p, nexthop, |
rtnh->rtnh_flags = 0; | routedesc, family, zvrf); |
rtnh->rtnh_hops = 0; | _netlink_route_build_multipath(routedesc, bytelen, |
rta->rta_len += rtnh->rtnh_len; | nexthop, rta, rtnh, &src); |
| |
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) | |
{ | |
if (IS_ZEBRA_DEBUG_KERNEL) | |
{ | |
zlog_debug ("netlink_route_multipath() " | |
"(recursive, multihop): %s %s/%d type %s", | |
lookup (nlmsg_str, cmd), | |
#ifdef HAVE_IPV6 | |
(family == AF_INET) ? inet_ntoa (p->u.prefix4) : | |
inet6_ntoa (p->u.prefix6), | |
#else | |
inet_ntoa (p->u.prefix4), | |
#endif /* HAVE_IPV6 */ | |
p->prefixlen, nexthop_type_to_str (nexthop->rtype)); | |
} | |
if (nexthop->rtype == NEXTHOP_TYPE_IPV4 | |
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) | |
{ | |
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, | |
&nexthop->rgate.ipv4, bytelen); | |
rtnh->rtnh_len += sizeof (struct rtattr) + 4; | |
| |
if (nexthop->src.ipv4.s_addr) | |
src = &nexthop->src; | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (recursive, " | |
"multihop): nexthop via %s if %u", | |
inet_ntoa (nexthop->rgate.ipv4), | |
nexthop->rifindex); | |
} | |
#ifdef HAVE_IPV6 | |
if (nexthop->rtype == NEXTHOP_TYPE_IPV6 | |
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME | |
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) | |
{ | |
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, | |
&nexthop->rgate.ipv6, bytelen); | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (recursive, " | |
"multihop): nexthop via %s if %u", | |
inet6_ntoa (nexthop->rgate.ipv6), | |
nexthop->rifindex); | |
} | |
#endif /* HAVE_IPV6 */ | |
/* ifindex */ | |
if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX | |
|| nexthop->rtype == NEXTHOP_TYPE_IFINDEX | |
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME) | |
{ | |
rtnh->rtnh_ifindex = nexthop->rifindex; | |
if (nexthop->src.ipv4.s_addr) | |
src = &nexthop->src; | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (recursive, " | |
"multihop): nexthop via if %u", | |
nexthop->rifindex); | |
} | |
else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX | |
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) | |
{ | |
rtnh->rtnh_ifindex = nexthop->rifindex; | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (recursive, " | |
"multihop): nexthop via if %u", | |
nexthop->rifindex); | |
} | |
else | |
{ | |
rtnh->rtnh_ifindex = 0; | |
} | |
} | |
else | |
{ | |
if (IS_ZEBRA_DEBUG_KERNEL) | |
{ | |
zlog_debug ("netlink_route_multipath() (multihop): " | |
"%s %s/%d, type %s", lookup (nlmsg_str, cmd), | |
#ifdef HAVE_IPV6 | |
(family == AF_INET) ? inet_ntoa (p->u.prefix4) : | |
inet6_ntoa (p->u.prefix6), | |
#else | |
inet_ntoa (p->u.prefix4), | |
#endif /* HAVE_IPV6 */ | |
p->prefixlen, nexthop_type_to_str (nexthop->type)); | |
} | |
if (nexthop->type == NEXTHOP_TYPE_IPV4 | |
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) | |
{ | |
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, | |
&nexthop->gate.ipv4, bytelen); | |
rtnh->rtnh_len += sizeof (struct rtattr) + 4; | |
| |
if (nexthop->src.ipv4.s_addr) | |
src = &nexthop->src; | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (multihop): " | |
"nexthop via %s if %u", | |
inet_ntoa (nexthop->gate.ipv4), | |
nexthop->ifindex); | |
} | |
#ifdef HAVE_IPV6 | |
if (nexthop->type == NEXTHOP_TYPE_IPV6 | |
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME | |
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) | |
{ | |
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, | |
&nexthop->gate.ipv6, bytelen); | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (multihop): " | |
"nexthop via %s if %u", | |
inet6_ntoa (nexthop->gate.ipv6), | |
nexthop->ifindex); | |
} | |
#endif /* HAVE_IPV6 */ | |
/* ifindex */ | |
if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX | |
|| nexthop->type == NEXTHOP_TYPE_IFINDEX | |
|| nexthop->type == NEXTHOP_TYPE_IFNAME) | |
{ | |
rtnh->rtnh_ifindex = nexthop->ifindex; | |
if (nexthop->src.ipv4.s_addr) | |
src = &nexthop->src; | |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (multihop): " | |
"nexthop via if %u", nexthop->ifindex); | |
} | |
else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME | |
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) | |
{ | |
rtnh->rtnh_ifindex = nexthop->ifindex; | |
| |
if (IS_ZEBRA_DEBUG_KERNEL) | |
zlog_debug("netlink_route_multipath() (multihop): " | |
"nexthop via if %u", nexthop->ifindex); | |
} | |
else | |
{ | |
rtnh->rtnh_ifindex = 0; | |
} | |
} | |
rtnh = RTNH_NEXT (rtnh); |
rtnh = RTNH_NEXT (rtnh); |
|
|
if (cmd == RTM_NEWROUTE) |
if (cmd == RTM_NEWROUTE) |
Line 1835 skip:
|
Line 1856 skip:
|
snl.nl_family = AF_NETLINK; |
snl.nl_family = AF_NETLINK; |
|
|
/* Talk to netlink socket. */ |
/* Talk to netlink socket. */ |
return netlink_talk (&req.n, &netlink_cmd); | return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf); |
} |
} |
|
|
int |
int |
kernel_add_ipv4 (struct prefix *p, struct rib *rib) | kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) |
{ |
{ |
return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET); | if (!old && new) |
} | return netlink_route_multipath (RTM_NEWROUTE, p, new); |
| if (old && !new) |
| return netlink_route_multipath (RTM_DELROUTE, p, old); |
|
|
int | /* Replace, can be done atomically if metric does not change; |
kernel_delete_ipv4 (struct prefix *p, struct rib *rib) | * netlink uses [prefix, tos, priority] to identify prefix. |
{ | * Now metric is not sent to kernel, so we can just do atomic replace. */ |
return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET); | return netlink_route_multipath (RTM_NEWROUTE, p, new); |
} |
} |
|
|
#ifdef HAVE_IPV6 |
|
int |
|
kernel_add_ipv6 (struct prefix *p, struct rib *rib) |
|
{ |
|
return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6); |
|
} |
|
|
|
int |
|
kernel_delete_ipv6 (struct prefix *p, struct rib *rib) |
|
{ |
|
return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); |
|
} |
|
|
|
/* Delete IPv6 route from the kernel. */ |
|
int |
|
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, |
|
unsigned int index, int flags, int table) |
|
{ |
|
return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, |
|
dest->prefixlen, gate, index, flags, table); |
|
} |
|
#endif /* HAVE_IPV6 */ |
|
|
|
/* Interface address modification. */ |
/* Interface address modification. */ |
static int |
static int |
netlink_address (int cmd, int family, struct interface *ifp, |
netlink_address (int cmd, int family, struct interface *ifp, |
Line 1888 netlink_address (int cmd, int family, struct interface
|
Line 1888 netlink_address (int cmd, int family, struct interface
|
char buf[NL_PKT_BUF_SIZE]; |
char buf[NL_PKT_BUF_SIZE]; |
} req; |
} req; |
|
|
|
struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); |
|
|
p = ifc->address; |
p = ifc->address; |
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); |
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); |
|
|
Line 1920 netlink_address (int cmd, int family, struct interface
|
Line 1922 netlink_address (int cmd, int family, struct interface
|
addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, |
addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, |
strlen (ifc->label) + 1); |
strlen (ifc->label) + 1); |
|
|
return netlink_talk (&req.n, &netlink_cmd); | return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf); |
} |
} |
|
|
int |
int |
Line 1942 extern struct thread_master *master;
|
Line 1944 extern struct thread_master *master;
|
static int |
static int |
kernel_read (struct thread *thread) |
kernel_read (struct thread *thread) |
{ |
{ |
netlink_parse_info (netlink_information_fetch, &netlink); | struct zebra_vrf *zvrf = (struct zebra_vrf *)THREAD_ARG (thread); |
thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); | netlink_parse_info (netlink_information_fetch, &zvrf->netlink, zvrf); |
| zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, |
| zvrf->netlink.sock); |
|
|
return 0; |
return 0; |
} |
} |
Line 1982 static void netlink_install_filter (int sock, __u32 pi
|
Line 1986 static void netlink_install_filter (int sock, __u32 pi
|
/* Exported interface function. This function simply calls |
/* Exported interface function. This function simply calls |
netlink_socket (). */ |
netlink_socket (). */ |
void |
void |
kernel_init (void) | kernel_init (struct zebra_vrf *zvrf) |
{ |
{ |
unsigned long groups; |
unsigned long groups; |
|
|
Line 1990 kernel_init (void)
|
Line 1994 kernel_init (void)
|
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR; |
groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR; |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
netlink_socket (&netlink, groups); | netlink_socket (&zvrf->netlink, groups, zvrf->vrf_id); |
netlink_socket (&netlink_cmd, 0); | netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id); |
|
|
/* Register kernel socket. */ |
/* Register kernel socket. */ |
if (netlink.sock > 0) | if (zvrf->netlink.sock > 0) |
{ |
{ |
/* Only want non-blocking on the netlink event socket */ |
/* Only want non-blocking on the netlink event socket */ |
if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0) | if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0) |
zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name, | zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name, |
safe_strerror (errno)); | safe_strerror (errno)); |
|
|
/* Set receive buffer size if it's set from command line */ |
/* Set receive buffer size if it's set from command line */ |
if (nl_rcvbufsize) |
if (nl_rcvbufsize) |
netlink_recvbuf (&netlink, nl_rcvbufsize); | netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize); |
|
|
netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid); | netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid); |
thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); | zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, |
| zvrf->netlink.sock); |
| } |
| } |
| |
| void |
| kernel_terminate (struct zebra_vrf *zvrf) |
| { |
| THREAD_READ_OFF (zvrf->t_netlink); |
| |
| if (zvrf->netlink.sock >= 0) |
| { |
| close (zvrf->netlink.sock); |
| zvrf->netlink.sock = -1; |
| } |
| |
| if (zvrf->netlink_cmd.sock >= 0) |
| { |
| close (zvrf->netlink_cmd.sock); |
| zvrf->netlink_cmd.sock = -1; |
} |
} |
} |
} |
|
|