1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008 |
- /* 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 "thread.h"
- #include "privs.h"
- #include "zebra/zserv.h"
- #include "zebra/rt.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;
- 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[] = {
- {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}
- };
- static const char *nexthop_types_desc[] =
- {
- "none",
- "Directly connected",
- "Interface route",
- "IPv4 nexthop",
- "IPv4 nexthop with ifindex",
- "IPv4 nexthop with ifname",
- "IPv6 nexthop",
- "IPv6 nexthop with ifindex",
- "IPv6 nexthop with ifname",
- "Null0 nexthop",
- };
- extern struct zebra_t zebrad;
- extern struct zebra_privs_t zserv_privs;
- extern u_int32_t nl_rcvbufsize;
- /* Note: on netlink systems, there should be a 1-to-1 mapping between interface
- names and ifindex values. */
- static void
- set_ifindex(struct interface *ifp, unsigned int ifi_index)
- {
- struct interface *oifp;
- if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
- {
- if (ifi_index == IFINDEX_INTERNAL)
- zlog_err("Netlink is setting interface %s ifindex to reserved "
- "internal value %u", ifp->name, ifi_index);
- else
- {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("interface index %d was renamed from %s to %s",
- ifi_index, oifp->name, ifp->name);
- if (if_is_up(oifp))
- zlog_err("interface rename detected on up interface: index %d "
- "was renamed from %s to %s, results are uncertain!",
- ifi_index, oifp->name, ifp->name);
- if_delete_update(oifp);
- }
- }
- ifp->ifindex = ifi_index;
- }
- /* Make socket for Linux netlink interface. */
- static int
- netlink_socket (struct nlsock *nl, unsigned long groups)
- {
- int ret;
- struct sockaddr_nl snl;
- int sock;
- int namelen;
- int save_errno;
- sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sock < 0)
- {
- zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
- safe_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,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
- /* Set receive buffer size if it's set from command line */
- if (nl_rcvbufsize)
- {
- u_int32_t oldsize, oldlen;
- u_int32_t newsize, newlen;
- oldlen = sizeof(oldsize);
- newlen = sizeof(newsize);
- ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
- ret = setsockopt(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,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
- ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
- zlog (NULL, LOG_INFO,
- "Setting netlink socket receive buffer size: %u -> %u",
- oldsize, newsize);
- }
- memset (&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
- snl.nl_groups = groups;
- /* 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);
- save_errno = errno;
- if (zserv_privs.change (ZPRIVS_LOWER))
- zlog (NULL, LOG_ERR, "Can't lower privileges");
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
- nl->name, snl.nl_groups, safe_strerror (save_errno));
- close (sock);
- return -1;
- }
- /* multiple netlink sockets will have different nl_pid */
- namelen = sizeof snl;
- ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
- if (ret < 0 || namelen != sizeof snl)
- {
- zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
- nl->snl = snl;
- nl->sock = sock;
- return ret;
- }
- static int
- set_netlink_blocking (struct nlsock *nl, int *flags)
- {
- /* Change socket flags for blocking I/O. */
- if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
- {
- zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
- __FUNCTION__, __LINE__, safe_strerror (errno));
- return -1;
- }
- *flags &= ~O_NONBLOCK;
- if (fcntl (nl->sock, F_SETFL, *flags) < 0)
- {
- zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
- __FUNCTION__, __LINE__, safe_strerror (errno));
- return -1;
- }
- return 0;
- }
- static int
- set_netlink_nonblocking (struct nlsock *nl, int *flags)
- {
- /* 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__, safe_strerror (errno));
- return -1;
- }
- return 0;
- }
- /* Get type specified information from netlink. */
- static int
- netlink_request (int family, int type, struct nlsock *nl)
- {
- int ret;
- struct sockaddr_nl snl;
- int save_errno;
- 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;
- memset (&req, 0, sizeof req);
- 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;
- /* linux appears to check capabilities on every message
- * have to raise caps for every message sent
- */
- if (zserv_privs.change (ZPRIVS_RAISE))
- {
- zlog (NULL, LOG_ERR, "Can't raise privileges");
- return -1;
- }
- ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
- (struct sockaddr *) &snl, sizeof snl);
- save_errno = errno;
- if (zserv_privs.change (ZPRIVS_LOWER))
- zlog (NULL, LOG_ERR, "Can't lower privileges");
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
- safe_strerror (save_errno));
- return -1;
- }
- return 0;
- }
- /* Receive message from netlink interface and pass those information
- to the given function. */
- static int
- netlink_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;
- int save_errno;
- if (zserv_privs.change (ZPRIVS_RAISE))
- zlog (NULL, LOG_ERR, "Can't raise privileges");
- status = recvmsg (nl->sock, &msg, 0);
- save_errno = errno;
- if (zserv_privs.change (ZPRIVS_LOWER))
- zlog (NULL, LOG_ERR, "Can't lower privileges");
- if (status < 0)
- {
- if (save_errno == EINTR)
- continue;
- if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
- break;
- zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
- nl->name, safe_strerror(save_errno));
- 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;
- }
-
- /* JF: Ignore messages that aren't from the kernel */
- if ( snl.nl_pid != 0 )
- {
- zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
- continue;
- }
- for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) 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_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
- __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;
- }
- /* Deal with Error Noise - MAG */
- {
- int loglvl = LOG_ERR;
- int errnum = err->error;
- int msg_type = err->msg.nlmsg_type;
- if (nl == &netlink_cmd
- && (-errnum == ENODEV || -errnum == ESRCH)
- && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
- loglvl = LOG_DEBUG;
- zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
- "seq=%u, pid=%u",
- nl->name, safe_strerror (-errnum),
- lookup (nlmsg_str, msg_type),
- msg_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_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
- 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_debug ("netlink_parse_info: %s packet comes from %s",
- netlink_cmd.name, nl->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 void
- netlink_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. */
- static int
- netlink_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);
-
- #ifdef IFLA_WIRELESS
- /* check for wireless messages to ignore */
- if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
- {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
- return 0;
- }
- #endif /* IFLA_WIRELESS */
- if (tb[IFLA_IFNAME] == NULL)
- return -1;
- name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
- /* Add interface. */
- ifp = if_get_by_name (name);
- set_ifindex(ifp, ifi->ifi_index);
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- ifp->mtu6 = 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. */
- static int
- netlink_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;
- void *broad;
- 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 (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
- {
- char buf[BUFSIZ];
- zlog_debug ("netlink_interface_addr %s %s:",
- lookup (nlmsg_str, h->nlmsg_type), ifp->name);
- if (tb[IFA_LOCAL])
- zlog_debug (" IFA_LOCAL %s/%d",
- inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
- buf, BUFSIZ), ifa->ifa_prefixlen);
- if (tb[IFA_ADDRESS])
- zlog_debug (" IFA_ADDRESS %s/%d",
- inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
- buf, BUFSIZ), ifa->ifa_prefixlen);
- if (tb[IFA_BROADCAST])
- zlog_debug (" IFA_BROADCAST %s/%d",
- inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
- buf, BUFSIZ), ifa->ifa_prefixlen);
- if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
- zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
-
- if (tb[IFA_CACHEINFO])
- {
- struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
- zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
- ci->ifa_prefered, ci->ifa_valid);
- }
- }
-
- /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
- if (tb[IFA_LOCAL] == NULL)
- tb[IFA_LOCAL] = tb[IFA_ADDRESS];
- if (tb[IFA_ADDRESS] == NULL)
- tb[IFA_ADDRESS] = tb[IFA_LOCAL];
-
- /* local interface address */
- addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
- /* is there a peer address? */
- if (tb[IFA_ADDRESS] &&
- memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
- {
- broad = RTA_DATA(tb[IFA_ADDRESS]);
- SET_FLAG (flags, ZEBRA_IFA_PEER);
- }
- else
- /* seeking a broadcast address */
- broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
- /* addr is primary key, SOL if we don't have one */
- if (addr == NULL)
- {
- zlog_debug ("%s: NULL address", __func__);
- return -1;
- }
- /* 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);
- }
- #ifdef HAVE_IPV6
- if (ifa->ifa_family == AF_INET6)
- {
- if (h->nlmsg_type == RTM_NEWADDR)
- connected_add_ipv6 (ifp, flags,
- (struct in6_addr *) addr, ifa->ifa_prefixlen,
- (struct in6_addr *) broad, label);
- else
- connected_delete_ipv6 (ifp,
- (struct in6_addr *) addr, ifa->ifa_prefixlen,
- (struct in6_addr *) broad);
- }
- #endif /* HAVE_IPV6 */
- return 0;
- }
- /* Looking up routing table by netlink interface. */
- static int
- netlink_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;
- int metric;
- void *dest;
- void *gate;
- void *src;
- 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 != zebrad.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;
- metric = 0;
- dest = NULL;
- gate = NULL;
- src = 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_PREFSRC])
- src = RTA_DATA (tb[RTA_PREFSRC]);
- /* Multipath treatment is needed. */
- if (tb[RTA_GATEWAY])
- gate = RTA_DATA (tb[RTA_GATEWAY]);
- if (tb[RTA_PRIORITY])
- metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
- 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, src, index, table, metric, 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,
- metric, 0);
- }
- #endif /* HAVE_IPV6 */
- return 0;
- }
- static const 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. */
- static int
- netlink_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;
- void *src;
- 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_debug ("%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 != zebrad.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;
- src = 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 (tb[RTA_PREFSRC])
- src = RTA_DATA (tb[RTA_PREFSRC]);
- 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_debug ("RTM_NEWROUTE %s/%d",
- inet_ntoa (p.prefix), p.prefixlen);
- else
- zlog_debug ("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, src, 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_debug ("RTM_NEWROUTE %s/%d",
- inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
- p.prefixlen);
- else
- zlog_debug ("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, 0, 0);
- else
- rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
- }
- #endif /* HAVE_IPV6 */
- return 0;
- }
- static int
- netlink_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);
- #ifdef IFLA_WIRELESS
- /* check for wireless messages to ignore */
- if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
- {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
- return 0;
- }
- #endif /* IFLA_WIRELESS */
-
- 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);
- set_ifindex(ifp, ifi->ifi_index);
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
- ifp->metric = 1;
- /* If new link is added. */
- if_add_update (ifp);
- }
- else
- {
- /* Interface status change. */
- set_ifindex(ifp, ifi->ifi_index);
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
- ifp->metric = 1;
- if (if_is_operative (ifp))
- {
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (!if_is_operative (ifp))
- if_down (ifp);
- else
- /* Must notify client daemons of new interface status. */
- zebra_interface_up_update (ifp);
- }
- else
- {
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (if_is_operative (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;
- }
- static int
- netlink_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. */
- int
- interface_lookup_netlink (void)
- {
- int ret;
- int flags;
- int snb_ret;
- /*
- * Change netlink socket flags to blocking to ensure we get
- * a reply via nelink_parse_info
- */
- snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
- if (snb_ret < 0)
- zlog (NULL, LOG_WARNING,
- "%s:%i Warning: Could not set netlink socket to blocking.",
- __FUNCTION__, __LINE__);
- /* 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 */
- /* restore socket flags */
- if (snb_ret == 0)
- set_netlink_nonblocking (&netlink_cmd, &flags);
- return 0;
- }
- /* Routing table read function using netlink interface. Only called
- bootstrap time. */
- int
- netlink_route_read (void)
- {
- int ret;
- int flags;
- int snb_ret;
- /*
- * Change netlink socket flags to blocking to ensure we get
- * a reply via nelink_parse_info
- */
- snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
- if (snb_ret < 0)
- zlog (NULL, LOG_WARNING,
- "%s:%i Warning: Could not set netlink socket to blocking.",
- __FUNCTION__, __LINE__);
- /* 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 */
- /* restore flags */
- if (snb_ret == 0)
- set_netlink_nonblocking (&netlink_cmd, &flags);
- return 0;
- }
- /* Utility function comes from iproute2.
- Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
- static int
- addattr_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;
- }
- static int
- rta_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> */
- static int
- addattr32 (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 int
- netlink_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(). */
- static int
- netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
- {
- int status;
- struct sockaddr_nl snl;
- struct iovec iov = { (void *) n, n->nlmsg_len };
- struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
- int flags = 0;
- int snb_ret;
- int save_errno;
- memset (&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
- n->nlmsg_seq = ++nl->seq;
- /* Request an acknowledgement by setting NLM_F_ACK */
- n->nlmsg_flags |= NLM_F_ACK;
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
- lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
- n->nlmsg_seq);
- /* Send message to netlink interface. */
- if (zserv_privs.change (ZPRIVS_RAISE))
- zlog (NULL, LOG_ERR, "Can't raise privileges");
- status = sendmsg (nl->sock, &msg, 0);
- save_errno = errno;
- if (zserv_privs.change (ZPRIVS_LOWER))
- zlog (NULL, LOG_ERR, "Can't lower privileges");
- if (status < 0)
- {
- zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
- safe_strerror (save_errno));
- return -1;
- }
- /*
- * Change socket flags for blocking I/O.
- * This ensures we wait for a reply in netlink_parse_info().
- */
- snb_ret = set_netlink_blocking (nl, &flags);
- if (snb_ret < 0)
- zlog (NULL, LOG_WARNING,
- "%s:%i Warning: Could not set netlink socket to blocking.",
- __FUNCTION__, __LINE__);
- /*
- * 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 */
- if (snb_ret == 0)
- set_netlink_nonblocking (nl, &flags);
- return status;
- }
- /* Routing table change via netlink interface. */
- static int
- netlink_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;
- req.r.rtm_protocol = RTPROT_ZEBRA;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
- if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- || (zebra_flags & ZEBRA_FLAG_REJECT))
- discard = 1;
- else
- discard = 0;
- if (cmd == RTM_NEWROUTE)
- {
- if (discard)
- {
- if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- req.r.rtm_type = RTN_BLACKHOLE;
- else if (zebra_flags & ZEBRA_FLAG_REJECT)
- req.r.rtm_type = RTN_UNREACHABLE;
- else
- assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
- }
- 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_cmd);
- if (ret < 0)
- return -1;
- return 0;
- }
- /* Routing table change via netlink interface. */
- static int
- netlink_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;
- 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;
- req.r.rtm_protocol = RTPROT_ZEBRA;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
- if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
- discard = 1;
- else
- discard = 0;
- if (cmd == RTM_NEWROUTE)
- {
- if (discard)
- {
- if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
- req.r.rtm_type = RTN_BLACKHOLE;
- else if (rib->flags & ZEBRA_FLAG_REJECT)
- req.r.rtm_type = RTN_UNREACHABLE;
- else
- assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
- }
- 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 (IS_ZEBRA_DEBUG_KERNEL)
- {
- 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_types_desc[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_types_desc[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)
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
- nexthop_num++;
- break;
- }
- }
- }
- else
- {
- char buf[1024];
- struct rtattr *rta = (void *) buf;
- struct rtnexthop *rtnh;
- union g_addr *src = NULL;
- 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 (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_types_desc[nexthop->rtype]);
- }
- 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;
- 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, 4096, 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_types_desc[nexthop->type]);
- }
- 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;
- 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, 4096, 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);
- if (cmd == RTM_NEWROUTE)
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
- }
- }
- if (src)
- addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
- 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_debug ("netlink_route_multipath(): No useful nexthop.");
- return 0;
- }
- skip:
- /* Destination netlink address. */
- memset (&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
- /* Talk to netlink socket. */
- return netlink_talk (&req.n, &netlink_cmd);
- }
- int
- kernel_add_ipv4 (struct prefix *p, struct rib *rib)
- {
- return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
- }
- int
- kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
- {
- return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
- }
- #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. */
- static int
- netlink_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 (!CONNECTED_PEER(ifc) && 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);
- }
- int
- kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
- {
- return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
- }
- int
- kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
- {
- return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
- }
- extern struct thread_master *master;
- /* Kernel route reflection. */
- static int
- kernel_read (struct thread *thread)
- {
- int ret;
- int sock;
- sock = THREAD_FD (thread);
- ret = netlink_parse_info (netlink_information_fetch, &netlink);
- thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
- return 0;
- }
- /* Filter out messages from self that occur on listener socket */
- static void netlink_install_filter (int sock)
- {
- /*
- * Filter is equivalent to netlink_route_change
- *
- * if (h->nlmsg_type == RTM_DELROUTE || h->nlmsg_type == RTM_NEWROUTE) {
- * if (rtm->rtm_type != RTM_UNICAST)
- * return 0;
- * 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;
- * }
- * return 0xffff;
- */
- struct sock_filter filter[] = {
- /* 0*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
- /* 1*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 1, 0),
- /* 2*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 11),
- /* 3*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
- sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_type)),
- /* 4*/ BPF_JUMP(BPF_JMP|BPF_B, RTN_UNICAST, 0, 8),
- /* 5*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
- sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_flags)),
- /* 6*/ BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, RTM_F_CLONED, 6, 0),
- /* 7*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
- sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_protocol)),
- /* 8*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_REDIRECT, 4, 0),
- /* 9*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_KERNEL, 0, 1),
- /*10*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_ZEBRA, 0, 3),
- /*11*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
- /*12*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 1),
- /*13*/ BPF_STMT(BPF_RET|BPF_K, 0), /* drop */
- /*14*/ BPF_STMT(BPF_RET|BPF_K, 0xffff), /* keep */
- };
- struct sock_fprog prog = {
- .len = sizeof(filter) / sizeof(filter[0]),
- .filter = filter,
- };
- if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
- zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
- }
- /* Exported interface function. This function simply calls
- netlink_socket (). */
- void
- kernel_init (void)
- {
- 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)
- {
- netlink_install_filter (netlink.sock);
- thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
- }
- }
|