📄 rt_netlink.c
字号:
struct iovec iov = { (void*) n, n->nlmsg_len }; struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0}; int flags = 0; memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; n->nlmsg_seq = ++netlink_cmd.seq; /* Request an acknowledgement by setting NLM_F_ACK */ n->nlmsg_flags |= NLM_F_ACK; if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name, lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type, n->nlmsg_seq); /* Send message to netlink interface. */ status = sendmsg (nl->sock, &msg, 0); if (status < 0) { zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s", strerror (errno)); return -1; } /* * Change socket flags for blocking I/O. * This ensures we wait for a reply in netlink_parse_info(). */ if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) { zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", __FUNCTION__, __LINE__, strerror (errno)); } flags &= ~O_NONBLOCK; if(fcntl(nl->sock, F_SETFL, flags) < 0) { zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", __FUNCTION__, __LINE__, strerror (errno)); } /* * Get reply from netlink socket. * The reply should either be an acknowlegement or an error. */ status = netlink_parse_info (netlink_talk_filter, nl); /* Restore socket flags for nonblocking I/O */ flags |= O_NONBLOCK; if(fcntl(nl->sock, F_SETFL, flags) < 0) { zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", __FUNCTION__, __LINE__, strerror (errno)); } return status;}/* Routing table change via netlink interface. */intnetlink_route (int cmd, int family, void *dest, int length, void *gate, int index, int zebra_flags, int table){ int ret; int bytelen; struct sockaddr_nl snl; int discard; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset (&req, 0, sizeof req); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = table; req.r.rtm_dst_len = length; if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) {#if 0 req.r.rtm_protocol = RTPROT_ZEBRA;#endif req.r.rtm_scope = RT_SCOPE_UNIVERSE; if (discard) req.r.rtm_type = RTN_BLACKHOLE; else req.r.rtm_type = RTN_UNICAST; } if (dest) addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); if (! discard) { if (gate) addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen); if (index > 0) addattr32 (&req.n, sizeof req, RTA_OIF, index); } /* Destination netlink address. */ memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; /* Talk to netlink socket. */ ret = netlink_talk (&req.n, &netlink); if (ret < 0) return -1; return 0;}/* Routing table change via netlink interface. */intnetlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, int family){ int bytelen; struct sockaddr_nl snl; struct nexthop *nexthop = NULL; int nexthop_num = 0; struct nlsock *nl; int discard; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset (&req, 0, sizeof req); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = rib->table; req.r.rtm_dst_len = p->prefixlen;#ifdef RTM_F_EQUALIZE req.r.rtm_flags |= RTM_F_EQUALIZE;#endif /* RTM_F_EQUALIZE */ if (rib->flags & ZEBRA_FLAG_BLACKHOLE) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { req.r.rtm_protocol = RTPROT_ZEBRA; req.r.rtm_scope = RT_SCOPE_UNIVERSE; if (discard) req.r.rtm_type = RTN_BLACKHOLE; else req.r.rtm_type = RTN_UNICAST; } addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); /* Metric. */ addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric); if (discard) { if (cmd == RTM_NEWROUTE) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); goto skip; } /* Multipath case. */ if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) { for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) addattr_l (&req.n, sizeof req, RTA_GATEWAY, &nexthop->rgate.ipv4, bytelen);#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);#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); } else { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) addattr_l (&req.n, sizeof req, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen);#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);#endif /* HAVE_IPV6 */ if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex); } if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); nexthop_num++; break; } } } else { char buf[1024]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); rtnh = RTA_DATA(rta); nexthop_num = 0; for (nexthop = rib->nexthop; nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM); nexthop = nexthop->next) { if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { nexthop_num++; rtnh->rtnh_len = sizeof (*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rta->rta_len += rtnh->rtnh_len; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { rta_addattr_l (rta, 4096, RTA_GATEWAY, &nexthop->rgate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + 4; }#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, 4096, RTA_GATEWAY, &nexthop->rgate.ipv6, bytelen);#endif /* HAVE_IPV6 */ /* ifindex */ 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) rtnh->rtnh_ifindex = nexthop->rifindex; else rtnh->rtnh_ifindex = 0; } else { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { rta_addattr_l (rta, 4096, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + 4; }#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, 4096, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen);#endif /* HAVE_IPV6 */ /* ifindex */ if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) rtnh->rtnh_ifindex = nexthop->ifindex; else rtnh->rtnh_ifindex = 0; } rtnh = RTNH_NEXT(rtnh); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } } if (rta->rta_len > RTA_LENGTH (0)) addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta)); } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("netlink_route_multipath(): No useful nexthop."); return 0; } skip: /* Destination netlink address. */ memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; if (family == AF_INET) nl = &netlink_cmd; else nl = &netlink; /* Talk to netlink socket. */ return netlink_talk (&req.n, nl);}intkernel_add_ipv4 (struct prefix *p, struct rib *rib){ return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);}intkernel_delete_ipv4 (struct prefix *p, struct rib *rib){ return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);}#ifdef HAVE_IPV6intkernel_add_ipv6 (struct prefix *p, struct rib *rib){ return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);}intkernel_delete_ipv6 (struct prefix *p, struct rib *rib){ return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);}/* Delete IPv6 route from the kernel. */intkernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, 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. */intnetlink_address (int cmd, int family, struct interface *ifp, struct connected *ifc){ int bytelen; struct prefix *p; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[1024]; } req; p = ifc->address; memset (&req, 0, sizeof req); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = family; req.ifa.ifa_index = ifp->ifindex; req.ifa.ifa_prefixlen = p->prefixlen; addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen); if (family == AF_INET && cmd == RTM_NEWADDR) { if (if_is_broadcast (ifp) && ifc->destination) { p = ifc->destination; addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen); } } if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY); if (ifc->label) addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, strlen (ifc->label) + 1); return netlink_talk (&req.n, &netlink_cmd);}intkernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc){ return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);}intkernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc){ return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);}#include "thread.h"extern struct thread_master *master;/* Kernel route reflection. */intkernel_read (struct thread *thread){ int ret; int sock; sock = THREAD_FD (thread); ret = netlink_parse_info (netlink_information_fetch, &netlink); thread_add_read (master, kernel_read, NULL, netlink.sock); return 0;}/* Exported interface function. This function simply calls netlink_socket (). */voidkernel_init (){ unsigned long groups; groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR;#ifdef HAVE_IPV6 groups |= RTMGRP_IPV6_ROUTE|RTMGRP_IPV6_IFADDR;#endif /* HAVE_IPV6 */ netlink_socket (&netlink, groups); netlink_socket (&netlink_cmd, 0); /* Register kernel socket. */ if (netlink.sock > 0) thread_add_read (master, kernel_read, NULL, netlink.sock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -