📄 kernel_socket.c
字号:
/* Kernel communication using routing socket. * Copyright (C) 1999 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>#include "if.h"#include "prefix.h"#include "sockunion.h"#include "connected.h"#include "memory.h"#include "ioctl.h"#include "log.h"#include "str.h"#include "table.h"#include "rib.h"#include "zebra/interface.h"#include "zebra/zserv.h"#include "zebra/debug.h"/* Socket length roundup function. */#define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))/* And this macro is wrapper for handling sa_len. */#ifdef HAVE_SA_LEN#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)#else#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr))#endif /* HAVE_SA_LEN *//* Routing socket message types. */struct message rtm_type_str[] ={ {RTM_ADD, "RTM_ADD"}, {RTM_DELETE, "RTM_DELETE"}, {RTM_CHANGE, "RTM_CHANGE"}, {RTM_GET, "RTM_GET"}, {RTM_LOSING, "RTM_LOSING"}, {RTM_REDIRECT, "RTM_REDIRECT"}, {RTM_MISS, "RTM_MISS"}, {RTM_LOCK, "RTM_LOCK"}, {RTM_OLDADD, "RTM_OLDADD"}, {RTM_OLDDEL, "RTM_OLDDEL"}, {RTM_RESOLVE, "RTM_RESOLVE"}, {RTM_NEWADDR, "RTM_NEWADDR"}, {RTM_DELADDR, "RTM_DELADDR"}, {RTM_IFINFO, "RTM_IFINFO"},#ifdef RTM_OIFINFO {RTM_OIFINFO, "RTM_OIFINFO"},#endif /* RTM_OIFINFO */#ifdef RTM_NEWMADDR {RTM_NEWMADDR, "RTM_NEWMADDR"},#endif /* RTM_NEWMADDR */#ifdef RTM_DELMADDR {RTM_DELMADDR, "RTM_DELMADDR"},#endif /* RTM_DELMADDR */#ifdef RTM_IFANNOUNCE {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},#endif /* RTM_IFANNOUNCE */ {0, NULL}};struct message rtm_flag_str[] ={ {RTF_UP, "UP"}, {RTF_GATEWAY, "GATEWAY"}, {RTF_HOST, "HOST"}, {RTF_REJECT, "REJECT"}, {RTF_DYNAMIC, "DYNAMIC"}, {RTF_MODIFIED, "MODIFIED"}, {RTF_DONE, "DONE"},#ifdef RTF_MASK {RTF_MASK, "MASK"},#endif /* RTF_MASK */ {RTF_CLONING, "CLONING"}, {RTF_XRESOLVE, "XRESOLVE"}, {RTF_LLINFO, "LLINFO"}, {RTF_STATIC, "STATIC"}, {RTF_BLACKHOLE, "BLACKHOLE"}, {RTF_PROTO1, "PROTO1"}, {RTF_PROTO2, "PROTO2"},#ifdef RTF_PRCLONING {RTF_PRCLONING, "PRCLONING"},#endif /* RTF_PRCLONING */#ifdef RTF_WASCLONED {RTF_WASCLONED, "WASCLONED"},#endif /* RTF_WASCLONED */#ifdef RTF_PROTO3 {RTF_PROTO3, "PROTO3"},#endif /* RTF_PROTO3 */#ifdef RTF_PINNED {RTF_PINNED, "PINNED"},#endif /* RTF_PINNED */#ifdef RTF_LOCAL {RTF_LOCAL, "LOCAL"},#endif /* RTF_LOCAL */#ifdef RTF_BROADCAST {RTF_BROADCAST, "BROADCAST"},#endif /* RTF_BROADCAST */#ifdef RTF_MULTICAST {RTF_MULTICAST, "MULTICAST"},#endif /* RTF_MULTICAST */ {0, NULL}};/* Kernel routing update socket. */int routing_sock = -1;/* Yes I'm checking ugly routing socket behavior. *//* #define DEBUG *//* Supported address family check. */static intaf_check (int family){ if (family == AF_INET) return 1;#ifdef HAVE_IPV6 if (family == AF_INET6) return 1;#endif /* HAVE_IPV6 */ return 0;}/* Dump routing table flag for debug purpose. */voidrtm_flag_dump (int flag){ struct message *mes; static char buf[BUFSIZ]; buf[0] = '0'; for (mes = rtm_flag_str; mes->key != 0; mes++) { if (mes->key & flag) { strlcat (buf, mes->str, BUFSIZ); strlcat (buf, " ", BUFSIZ); } } zlog_info ("Kernel: %s", buf);}#ifdef RTM_IFANNOUNCE/* Interface adding function */intifan_read (struct if_announcemsghdr *ifan){ struct interface *ifp; ifp = if_lookup_by_index (ifan->ifan_index); if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL) { /* Create Interface */ ifp = if_get_by_name (ifan->ifan_name); ifp->ifindex = ifan->ifan_index; if_add_update (ifp); } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) { if_delete_update (ifp); if_delete (ifp); } if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); return 0;}#endif /* RTM_IFANNOUNCE *//* Interface adding function called from interface_list. */intifm_read (struct if_msghdr *ifm){ struct interface *ifp; struct sockaddr_dl *sdl = NULL; sdl = (struct sockaddr_dl *)(ifm + 1); /* Use sdl index. */ ifp = if_lookup_by_index (ifm->ifm_index); if (ifp == NULL) { /* Check interface's address.*/ if (! (ifm->ifm_addrs & RTA_IFP)) { zlog_warn ("There must be RTA_IFP address for ifindex %d\n", ifm->ifm_index); return -1; } ifp = if_create (); strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen); ifp->ifindex = ifm->ifm_index; ifp->flags = ifm->ifm_flags;#if defined(__bsdi__) if_kvm_get_mtu (ifp);#else if_get_mtu (ifp);#endif /* __bsdi__ */ if_get_metric (ifp); /* Fetch hardware address. */ if (sdl->sdl_family != AF_LINK) { zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK"); return -1; } memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); if_add_update (ifp); } else { /* There is a case of promisc, allmulti flag modification. */ if (if_is_up (ifp)) { ifp->flags = ifm->ifm_flags; if (! if_is_up (ifp)) if_down (ifp); } else { ifp->flags = ifm->ifm_flags; if (if_is_up (ifp)) if_up (ifp); } } #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data;#endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); return 0;}/* Address read from struct ifa_msghdr. */voidifam_read_mesg (struct ifa_msghdr *ifm, union sockunion *addr, union sockunion *mask, union sockunion *dest){ caddr_t pnt, end; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen;#define IFAMADDRGET(X,R) \ if (ifm->ifam_addrs & (R)) \ { \ int len = WRAPUP(pnt); \ if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ memcpy ((caddr_t)(X), pnt, len); \ pnt += len; \ }#define IFAMMASKGET(X,R) \ if (ifm->ifam_addrs & (R)) \ { \ int len = WRAPUP(pnt); \ if ((X) != NULL) \ memcpy ((caddr_t)(X), pnt, len); \ pnt += len; \ } /* Be sure structure is cleared */ memset (mask, 0, sizeof (union sockunion)); memset (addr, 0, sizeof (union sockunion)); memset (dest, 0, sizeof (union sockunion)); /* We fetch each socket variable into sockunion. */ IFAMADDRGET (NULL, RTA_DST); IFAMADDRGET (NULL, RTA_GATEWAY); IFAMMASKGET (mask, RTA_NETMASK); IFAMADDRGET (NULL, RTA_GENMASK); IFAMADDRGET (NULL, RTA_IFP); IFAMADDRGET (addr, RTA_IFA); IFAMADDRGET (NULL, RTA_AUTHOR); IFAMADDRGET (dest, RTA_BRD); /* Assert read up end point matches to end point */ if (pnt != end) zlog_warn ("ifam_read() does't read all socket data");}/* Interface's address information get. */intifam_read (struct ifa_msghdr *ifam){ struct interface *ifp; union sockunion addr, mask, gate; /* Check does this interface exist or not. */ ifp = if_lookup_by_index (ifam->ifam_index); if (ifp == NULL) { zlog_warn ("no interface for index %d", ifam->ifam_index); return -1; } /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &gate); /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &gate.sin.sin_addr, NULL); else connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &gate.sin.sin_addr, NULL); break;#ifdef HAVE_IPV6 case AF_INET6: /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &gate.sin6.sin6_addr); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &gate.sin6.sin6_addr); break;#endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } return 0;}/* Interface function for reading kernel routing table information. */intrtm_read_mesg (struct rt_msghdr *rtm, union sockunion *dest, union sockunion *mask, union sockunion *gate){ caddr_t pnt, end; /* Pnt points out socket data start point. */ pnt = (caddr_t)(rtm + 1); end = ((caddr_t)rtm) + rtm->rtm_msglen; /* rt_msghdr version check. */ if (rtm->rtm_version != RTM_VERSION) zlog (NULL, LOG_WARNING, "Routing message version different %d should be %d." "This may cause problem\n", rtm->rtm_version, RTM_VERSION);#define RTMADDRGET(X,R) \ if (rtm->rtm_addrs & (R)) \ { \ int len = WRAPUP (pnt); \ if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ memcpy ((caddr_t)(X), pnt, len); \ pnt += len; \ }#define RTMMASKGET(X,R) \ if (rtm->rtm_addrs & (R)) \ { \ int len = WRAPUP (pnt); \ if ((X) != NULL) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -