⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rt_netlink.c

📁 大名鼎鼎的路由器源码。程序分ZEBRA、OSPFRIP等3个包。程序框架采用一个路由协议一个进程的方式
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Kernel routing table updates using netlink over GNU/Linux system. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING.  If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA.   */#include <zebra.h>/* Hack for GNU libc version 2. */#ifndef MSG_TRUNC#define MSG_TRUNC      0x20#endif /* MSG_TRUNC */#include "linklist.h"#include "if.h"#include "log.h"#include "prefix.h"#include "connected.h"#include "table.h"#include "rib.h"#include "zebra/zserv.h"#include "zebra/redistribute.h"#include "zebra/interface.h"#include "zebra/debug.h"/* Socket interface to kernel */struct nlsock{  int sock;  int seq;  struct sockaddr_nl snl;  char *name;} netlink =	{ -1, 0, {0}, "netlink-listen" },	/* kernel messages */  netlink_cmd = { -1, 0, {0}, "netlink-cmd" },          /* command channel */  netlink_addr = {-1, 0, {0}, "netlink-addr" };		/* address channel */struct message nlmsg_str[] ={  {RTM_NEWROUTE, "RTM_NEWROUTE"},  {RTM_DELROUTE, "RTM_DELROUTE"},  {RTM_GETROUTE, "RTM_GETROUTE"},  {RTM_NEWLINK,  "RTM_NEWLINK"},  {RTM_DELLINK,  "RTM_DELLINK"},  {RTM_GETLINK,  "RTM_GETLINK"},  {RTM_NEWADDR,  "RTM_NEWADDR"},  {RTM_DELADDR,  "RTM_DELADDR"},  {RTM_GETADDR,  "RTM_GETADDR"},  {0,            NULL}};extern int rtm_table_default;/* Make socket for Linux netlink interface. */static intnetlink_socket (struct nlsock *nl, unsigned long groups){  int ret;  struct sockaddr_nl snl;  int sock;  int namelen;  sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);  if (sock < 0)    {      zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,	    strerror (errno));      return -1;    }  ret = fcntl (sock, F_SETFL, O_NONBLOCK);  if (ret < 0)    {      zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,	    strerror (errno));      close (sock);      return -1;    }    memset (&snl, 0, sizeof snl);  snl.nl_family = AF_NETLINK;  snl.nl_groups = groups;  /* Bind the socket to the netlink structure for anything. */  ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);  if (ret < 0)    {      zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", 	    nl->name, snl.nl_groups, strerror (errno));      close (sock);      return -1;    }  /* multiple netlink sockets will have different nl_pid */  namelen = sizeof snl;  ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);  if (ret < 0 || namelen != sizeof snl)    {      zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,	    strerror (errno));      close (sock);      return -1;    }  nl->snl = snl;  nl->sock = sock;  return ret;}/* Get type specified information from netlink. */static intnetlink_request (int family, int type, struct nlsock *nl){  int ret;  struct sockaddr_nl snl;  struct  {    struct nlmsghdr nlh;    struct rtgenmsg g;  } req;  /* Check netlink socket. */  if (nl->sock < 0)    {      zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);      return -1;    }  memset (&snl, 0, sizeof snl);  snl.nl_family = AF_NETLINK;  req.nlh.nlmsg_len = sizeof req;  req.nlh.nlmsg_type = type;  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;  req.nlh.nlmsg_pid = 0;  req.nlh.nlmsg_seq = ++nl->seq;  req.g.rtgen_family = family;   ret = sendto (nl->sock, (void*) &req, sizeof req, 0, 		(struct sockaddr*) &snl, sizeof snl);  if (ret < 0)    {      zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno));      return -1;    }  return 0;}/* Receive message from netlink interface and pass those information   to the given function. */static intnetlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),		    struct nlsock *nl){  int status;  int ret = 0;  int error;  while (1)    {      char buf[4096];      struct iovec iov = { buf, sizeof buf };      struct sockaddr_nl snl;      struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};      struct nlmsghdr *h;      status = recvmsg (nl->sock, &msg, 0);      if (status < 0)	{	  if (errno == EINTR)	    continue;	  if (errno == EWOULDBLOCK || errno == EAGAIN)	    break;	  zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);	  continue;	}      if (snl.nl_pid != 0)	{	  zlog (NULL, LOG_ERR, "Ignoring non kernel message from pid %u",		snl.nl_pid);	  continue;	}      if (status == 0)	{	  zlog (NULL, LOG_ERR, "%s EOF", nl->name);	  return -1;	}      if (msg.msg_namelen != sizeof snl)	{	  zlog (NULL, LOG_ERR, "%s sender address length error: length %d",	       nl->name, msg.msg_namelen);	  return -1;	}      for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status); 	   h = NLMSG_NEXT (h, status))	{	  /* Finish of reading. */	  if (h->nlmsg_type == NLMSG_DONE)	    return ret;	  /* Error handling. */	  if (h->nlmsg_type == NLMSG_ERROR)	    {	      struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);	                    /* If the error field is zero, then this is an ACK */              if (err->error == 0)                 {                  if (IS_ZEBRA_DEBUG_KERNEL)                     {                        zlog_info("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",                         __FUNCTION__, nl->name,                        lookup (nlmsg_str, err->msg.nlmsg_type),                        err->msg.nlmsg_type, err->msg.nlmsg_seq,		        err->msg.nlmsg_pid);                    }                                  /* return if not a multipart message, otherwise continue */                    if(!(h->nlmsg_flags & NLM_F_MULTI))                     {                       return 0;                        }                  continue;                 }                            if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))		{		  zlog (NULL, LOG_ERR, "%s error: message truncated",			nl->name);		  return -1;		}	      zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d",		    nl->name, strerror (-err->error),		    lookup (nlmsg_str, err->msg.nlmsg_type),		    err->msg.nlmsg_type, err->msg.nlmsg_seq,		    err->msg.nlmsg_pid);	      /*	      ret = -1;	      continue;	      */	      return -1;	    }	  /* OK we got netlink message. */	  if (IS_ZEBRA_DEBUG_KERNEL)	    zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",		      nl->name,		      lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,		      h->nlmsg_seq, h->nlmsg_pid);	  /* skip unsolicited messages originating from command socket */	  if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)	    {	      if (IS_ZEBRA_DEBUG_KERNEL)		zlog_info ("netlink_parse_info: %s packet comes from %s",			  nl->name, netlink_cmd.name);	      continue;	    }	  error = (*filter) (&snl, h);	  if (error < 0)	    {	      zlog (NULL, LOG_ERR, "%s filter function error", nl->name);	      ret = error;	    }	}      /* After error care. */      if (msg.msg_flags & MSG_TRUNC)	{	  zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);	  continue;	}      if (status)	{	  zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,		status);	  return -1;	}    }  return ret;}/* Utility function for parse rtattr. */static voidnetlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len){  while (RTA_OK(rta, len))     {      if (rta->rta_type <= max)	tb[rta->rta_type] = rta;      rta = RTA_NEXT(rta,len);    }}/* Called from interface_lookup_netlink().  This function is only used   during bootstrap. */intnetlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h){  int len;  struct ifinfomsg *ifi;  struct rtattr *tb[IFLA_MAX + 1];  struct interface *ifp;  char *name;  int i;  ifi = NLMSG_DATA (h);  if (h->nlmsg_type != RTM_NEWLINK)    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. */  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;  /* Hardware type and address. */  ifp->hw_type = ifi->ifi_type;  if (tb[IFLA_ADDRESS])    {      int hw_addr_len;      hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);      if (hw_addr_len > INTERFACE_HWADDR_MAX)	zlog_warn ("Hardware address is too large: %d", hw_addr_len);      else	{      	  ifp->hw_addr_len = hw_addr_len;	  memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len);	  for (i = 0; i < hw_addr_len; i++)	    if (ifp->hw_addr[i] != 0)	      break;	  if (i == hw_addr_len)	    ifp->hw_addr_len = 0;	  else	    ifp->hw_addr_len = hw_addr_len;	}    }  if_add_update (ifp);  return 0;}/* Lookup interface IPv4/IPv6 address. */intnetlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h){  int len;  struct ifaddrmsg *ifa;  struct rtattr *tb [IFA_MAX + 1];  struct interface *ifp;  void *addr = NULL;  void *broad = NULL;  u_char flags = 0;  char *label = NULL;  ifa = NLMSG_DATA (h);  if (ifa->ifa_family != AF_INET #ifdef HAVE_IPV6      && ifa->ifa_family != AF_INET6#endif /* HAVE_IPV6 */      )    return 0;  if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)    return 0;  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg));  if (len < 0)    return -1;  memset (tb, 0, sizeof tb);  netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);  ifp = if_lookup_by_index (ifa->ifa_index);  if (ifp == NULL)    {      zlog_err ("netlink_interface_addr can't find interface by index %d",		ifa->ifa_index);      return -1;    }  if (tb[IFA_ADDRESS] == NULL)    tb[IFA_ADDRESS] = tb[IFA_LOCAL];  if (ifp->flags & IFF_POINTOPOINT)    {      if (tb[IFA_LOCAL])	{	  addr = RTA_DATA (tb[IFA_LOCAL]);	  if (tb[IFA_ADDRESS]) 	    broad = RTA_DATA (tb[IFA_ADDRESS]);	  else	    broad = NULL;	}      else	{	  if (tb[IFA_ADDRESS])	    addr = RTA_DATA (tb[IFA_ADDRESS]);	  else	    addr = NULL;	}    }  else    {      if (tb[IFA_ADDRESS])	addr = RTA_DATA (tb[IFA_ADDRESS]);      else	addr = NULL;      if (tb[IFA_BROADCAST])	broad = RTA_DATA(tb[IFA_BROADCAST]);      else	broad = NULL;    }  /* Flags. */  if (ifa->ifa_flags & IFA_F_SECONDARY)    SET_FLAG (flags, ZEBRA_IFA_SECONDARY);  /* Label */  if (tb[IFA_LABEL])    label = (char *) RTA_DATA (tb[IFA_LABEL]);  if (ifp && label && strcmp (ifp->name, label) == 0)    label = NULL;  /* Register interface address to the interface. */  if (ifa->ifa_family == AF_INET)    {      if (h->nlmsg_type == RTM_NEWADDR) 	connected_add_ipv4 (ifp, flags,			    (struct in_addr *) addr, ifa->ifa_prefixlen, 			    (struct in_addr *) broad, label);      else 	connected_delete_ipv4 (ifp, flags,			       (struct in_addr *) addr, ifa->ifa_prefixlen, 			       (struct in_addr *) broad, label);    }#ifdef HAVE_IPV6  if (ifa->ifa_family == AF_INET6)    {      if (h->nlmsg_type == RTM_NEWADDR)	connected_add_ipv6 (ifp, 			    (struct in6_addr *) addr, ifa->ifa_prefixlen, 			    (struct in6_addr *) broad);      else	connected_delete_ipv6 (ifp, 			       (struct in6_addr *) addr, ifa->ifa_prefixlen, 			       (struct in6_addr *) broad);    }#endif /* HAVE_IPV6*/  return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -