📄 rt_netlink.c
字号:
/* Looking up routing table by netlink interface. */intnetlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h){ int len; struct rtmsg *rtm; struct rtattr *tb [RTA_MAX + 1]; u_char flags = 0; char anyaddr[16] = {0}; int index; int table; void *dest; void *gate; rtm = NLMSG_DATA (h); if (h->nlmsg_type != RTM_NEWROUTE) return 0; if (rtm->rtm_type != RTN_UNICAST) return 0; table = rtm->rtm_table;#if 0 /* we weed them out later in rib_weed_tables () */ if (table != RT_TABLE_MAIN && table != rtm_table_default) return 0;#endif len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); if (rtm->rtm_flags & RTM_F_CLONED) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; if (rtm->rtm_protocol == RTPROT_KERNEL) return 0; if (rtm->rtm_src_len != 0) return 0; /* Route which inserted by Zebra. */ if (rtm->rtm_protocol == RTPROT_ZEBRA) flags |= ZEBRA_FLAG_SELFROUTE; index = 0; dest = NULL; gate = NULL; if (tb[RTA_OIF]) index = *(int *) RTA_DATA (tb[RTA_OIF]); if (tb[RTA_DST]) dest = RTA_DATA (tb[RTA_DST]); else dest = anyaddr; /* Multipath treatment is needed. */ if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0); }#ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table); }#endif /* HAVE_IPV6 */ return 0;}struct message rtproto_str [] = { {RTPROT_REDIRECT, "redirect"}, {RTPROT_KERNEL, "kernel"}, {RTPROT_BOOT, "boot"}, {RTPROT_STATIC, "static"}, {RTPROT_GATED, "GateD"}, {RTPROT_RA, "router advertisement"}, {RTPROT_MRT, "MRT"}, {RTPROT_ZEBRA, "Zebra"},#ifdef RTPROT_BIRD {RTPROT_BIRD, "BIRD"},#endif /* RTPROT_BIRD */ {0, NULL}};/* Routing information change from the kernel. */intnetlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h){ int len; struct rtmsg *rtm; struct rtattr *tb [RTA_MAX + 1]; char anyaddr[16] = {0}; int index; int table; void *dest; void *gate; rtm = NLMSG_DATA (h); if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { /* If this is not route add/delete message print warning. */ zlog_warn ("Kernel message: %d\n", h->nlmsg_type); return 0; } /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("%s %s %s proto %s", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", lookup (rtproto_str, rtm->rtm_protocol)); if (rtm->rtm_type != RTN_UNICAST) { return 0; } table = rtm->rtm_table; if (table != RT_TABLE_MAIN && table != rtm_table_default) { return 0; } len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); if (rtm->rtm_flags & RTM_F_CLONED) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; if (rtm->rtm_protocol == RTPROT_KERNEL) return 0; if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE) return 0; if (rtm->rtm_src_len != 0) { zlog_warn ("netlink_route_change(): no src len"); return 0; } index = 0; dest = NULL; gate = NULL; if (tb[RTA_OIF]) index = *(int *) RTA_DATA (tb[RTA_OIF]); if (tb[RTA_DST]) dest = RTA_DATA (tb[RTA_DST]); else dest = anyaddr; if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_info ("RTM_NEWROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); else zlog_info ("RTM_DELROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); }#ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; char buf[BUFSIZ]; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_info ("RTM_NEWROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); else zlog_info ("RTM_DELROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); }#endif /* HAVE_IPV6 */ return 0;}intnetlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h){ int len; struct ifinfomsg *ifi; struct rtattr *tb [IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *)RTA_DATA(tb[IFLA_IFNAME]); /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); ifp->ifindex = ifi->ifi_index; ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; /* If new link is added. */ if_add_update(ifp); } else { /* Interface status change. */ ifp->ifindex = ifi->ifi_index; ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; if (if_is_up (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (! if_is_up (ifp)) if_down (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_up (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", name); return 0; } if_delete_update (ifp); } return 0;}intnetlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h){ switch (h->nlmsg_type) { case RTM_NEWROUTE: return netlink_route_change (snl, h); break; case RTM_DELROUTE: return netlink_route_change (snl, h); break; case RTM_NEWLINK: return netlink_link_change (snl, h); break; case RTM_DELLINK: return netlink_link_change (snl, h); break; case RTM_NEWADDR: return netlink_interface_addr (snl, h); break; case RTM_DELADDR: return netlink_interface_addr (snl, h); break; default: zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type); break; } return 0;}/* Interface lookup by netlink socket. */intinterface_lookup_netlink (){ int ret; /* Get interface information. */ ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface, &netlink_cmd); if (ret < 0) return ret; /* Get IPv4 address of the interfaces. */ ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); if (ret < 0) return ret;#ifdef HAVE_IPV6 /* Get IPv6 address of the interfaces. */ ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); if (ret < 0) return ret;#endif /* HAVE_IPV6 */ return 0;}/* Routing table read function using netlink interface. Only called bootstrap time. */intnetlink_route_read (){ int ret; /* Get IPv4 routing table. */ ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); if (ret < 0) return ret;#ifdef HAVE_IPV6 /* Get IPv6 routing table. */ ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); if (ret < 0) return ret;#endif /* HAVE_IPV6 */ return 0;}/* Utility function comes from iproute2. Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */intaddattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen){ int len; struct rtattr *rta; len = RTA_LENGTH(alen); if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA(rta), data, alen); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0;}intrta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen){ int len; struct rtattr *subrta; len = RTA_LENGTH(alen); if (RTA_ALIGN(rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy (RTA_DATA(subrta), data, alen); rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len; return 0;}/* Utility function comes from iproute2. Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */intaddattr32 (struct nlmsghdr *n, int maxlen, int type, int data){ int len; struct rtattr *rta; len = RTA_LENGTH(4); if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA(rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0;}static intnetlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h){ zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); return 0;}/* sendmsg() to netlink socket then recvmsg(). */intnetlink_talk (struct nlmsghdr *n, struct nlsock *nl){ int status; struct sockaddr_nl snl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -