Annotation of embedaddon/quagga/zebra/rt_netlink.c, revision 1.1.1.4
1.1 misho 1: /* Kernel routing table updates using netlink over GNU/Linux system.
2: * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3: *
4: * This file is part of GNU Zebra.
5: *
6: * GNU Zebra is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2, or (at your option) any
9: * later version.
10: *
11: * GNU Zebra is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with GNU Zebra; see the file COPYING. If not, write to the Free
18: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19: * 02111-1307, USA.
20: */
21:
22: #include <zebra.h>
1.1.1.4 ! misho 23: #include <net/if_arp.h>
1.1 misho 24:
25: /* Hack for GNU libc version 2. */
26: #ifndef MSG_TRUNC
27: #define MSG_TRUNC 0x20
28: #endif /* MSG_TRUNC */
29:
30: #include "linklist.h"
31: #include "if.h"
32: #include "log.h"
33: #include "prefix.h"
34: #include "connected.h"
35: #include "table.h"
1.1.1.2 misho 36: #include "memory.h"
1.1 misho 37: #include "rib.h"
38: #include "thread.h"
39: #include "privs.h"
1.1.1.4 ! misho 40: #include "vrf.h"
1.1 misho 41:
42: #include "zebra/zserv.h"
43: #include "zebra/rt.h"
44: #include "zebra/redistribute.h"
45: #include "zebra/interface.h"
46: #include "zebra/debug.h"
47:
1.1.1.3 misho 48: #include "rt_netlink.h"
1.1.1.2 misho 49:
1.1 misho 50: static const struct message nlmsg_str[] = {
51: {RTM_NEWROUTE, "RTM_NEWROUTE"},
52: {RTM_DELROUTE, "RTM_DELROUTE"},
53: {RTM_GETROUTE, "RTM_GETROUTE"},
54: {RTM_NEWLINK, "RTM_NEWLINK"},
55: {RTM_DELLINK, "RTM_DELLINK"},
56: {RTM_GETLINK, "RTM_GETLINK"},
57: {RTM_NEWADDR, "RTM_NEWADDR"},
58: {RTM_DELADDR, "RTM_DELADDR"},
59: {RTM_GETADDR, "RTM_GETADDR"},
60: {0, NULL}
61: };
62:
63: extern struct zebra_t zebrad;
64:
65: extern struct zebra_privs_t zserv_privs;
66:
67: extern u_int32_t nl_rcvbufsize;
68:
69: /* Note: on netlink systems, there should be a 1-to-1 mapping between interface
70: names and ifindex values. */
71: static void
1.1.1.4 ! misho 72: set_ifindex(struct interface *ifp, ifindex_t ifi_index)
1.1 misho 73: {
74: struct interface *oifp;
75:
76: if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
77: {
78: if (ifi_index == IFINDEX_INTERNAL)
79: zlog_err("Netlink is setting interface %s ifindex to reserved "
80: "internal value %u", ifp->name, ifi_index);
81: else
82: {
83: if (IS_ZEBRA_DEBUG_KERNEL)
84: zlog_debug("interface index %d was renamed from %s to %s",
85: ifi_index, oifp->name, ifp->name);
86: if (if_is_up(oifp))
87: zlog_err("interface rename detected on up interface: index %d "
88: "was renamed from %s to %s, results are uncertain!",
89: ifi_index, oifp->name, ifp->name);
90: if_delete_update(oifp);
91: }
92: }
93: ifp->ifindex = ifi_index;
94: }
95:
1.1.1.4 ! misho 96: #ifndef SO_RCVBUFFORCE
! 97: #define SO_RCVBUFFORCE (33)
! 98: #endif
! 99:
1.1 misho 100: static int
101: netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
102: {
103: u_int32_t oldsize;
104: socklen_t newlen = sizeof(newsize);
105: socklen_t oldlen = sizeof(oldsize);
106: int ret;
107:
108: ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
109: if (ret < 0)
110: {
111: zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
112: safe_strerror (errno));
113: return -1;
114: }
115:
1.1.1.4 ! misho 116: /* Try force option (linux >= 2.6.14) and fall back to normal set */
! 117: if ( zserv_privs.change (ZPRIVS_RAISE) )
! 118: zlog_err ("routing_socket: Can't raise privileges");
! 119: ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize,
1.1 misho 120: sizeof(nl_rcvbufsize));
1.1.1.4 ! misho 121: if ( zserv_privs.change (ZPRIVS_LOWER) )
! 122: zlog_err ("routing_socket: Can't lower privileges");
! 123: if (ret < 0)
! 124: ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
! 125: sizeof(nl_rcvbufsize));
1.1 misho 126: if (ret < 0)
127: {
128: zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
129: safe_strerror (errno));
130: return -1;
131: }
132:
133: ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
134: if (ret < 0)
135: {
136: zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
137: safe_strerror (errno));
138: return -1;
139: }
140:
141: zlog (NULL, LOG_INFO,
142: "Setting netlink socket receive buffer size: %u -> %u",
143: oldsize, newsize);
144: return 0;
145: }
146:
147: /* Make socket for Linux netlink interface. */
148: static int
1.1.1.4 ! misho 149: netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id)
1.1 misho 150: {
151: int ret;
152: struct sockaddr_nl snl;
153: int sock;
154: int namelen;
155: int save_errno;
156:
1.1.1.4 ! misho 157: if (zserv_privs.change (ZPRIVS_RAISE))
! 158: {
! 159: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 160: return -1;
! 161: }
! 162:
! 163: sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id);
1.1 misho 164: if (sock < 0)
165: {
166: zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
167: safe_strerror (errno));
168: return -1;
169: }
170:
171: memset (&snl, 0, sizeof snl);
172: snl.nl_family = AF_NETLINK;
173: snl.nl_groups = groups;
174:
175: /* Bind the socket to the netlink structure for anything. */
176: ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
177: save_errno = errno;
178: if (zserv_privs.change (ZPRIVS_LOWER))
179: zlog (NULL, LOG_ERR, "Can't lower privileges");
180:
181: if (ret < 0)
182: {
183: zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
184: nl->name, snl.nl_groups, safe_strerror (save_errno));
185: close (sock);
186: return -1;
187: }
188:
189: /* multiple netlink sockets will have different nl_pid */
190: namelen = sizeof snl;
191: ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
192: if (ret < 0 || namelen != sizeof snl)
193: {
194: zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
195: safe_strerror (errno));
196: close (sock);
197: return -1;
198: }
199:
200: nl->snl = snl;
201: nl->sock = sock;
202: return ret;
203: }
204:
205: /* Get type specified information from netlink. */
206: static int
207: netlink_request (int family, int type, struct nlsock *nl)
208: {
209: int ret;
210: struct sockaddr_nl snl;
211: int save_errno;
212:
213: struct
214: {
215: struct nlmsghdr nlh;
216: struct rtgenmsg g;
217: } req;
218:
219:
220: /* Check netlink socket. */
221: if (nl->sock < 0)
222: {
223: zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
224: return -1;
225: }
226:
227: memset (&snl, 0, sizeof snl);
228: snl.nl_family = AF_NETLINK;
229:
230: memset (&req, 0, sizeof req);
231: req.nlh.nlmsg_len = sizeof req;
232: req.nlh.nlmsg_type = type;
233: req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
234: req.nlh.nlmsg_pid = nl->snl.nl_pid;
235: req.nlh.nlmsg_seq = ++nl->seq;
236: req.g.rtgen_family = family;
237:
238: /* linux appears to check capabilities on every message
239: * have to raise caps for every message sent
240: */
241: if (zserv_privs.change (ZPRIVS_RAISE))
242: {
243: zlog (NULL, LOG_ERR, "Can't raise privileges");
244: return -1;
245: }
246:
247: ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
248: (struct sockaddr *) &snl, sizeof snl);
249: save_errno = errno;
250:
251: if (zserv_privs.change (ZPRIVS_LOWER))
252: zlog (NULL, LOG_ERR, "Can't lower privileges");
253:
254: if (ret < 0)
255: {
256: zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
257: safe_strerror (save_errno));
258: return -1;
259: }
260:
261: return 0;
262: }
263:
264: /* Receive message from netlink interface and pass those information
265: to the given function. */
266: static int
1.1.1.4 ! misho 267: netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
! 268: vrf_id_t),
! 269: struct nlsock *nl, struct zebra_vrf *zvrf)
1.1 misho 270: {
271: int status;
272: int ret = 0;
273: int error;
274:
275: while (1)
276: {
1.1.1.2 misho 277: char buf[NL_PKT_BUF_SIZE];
1.1.1.4 ! misho 278: struct iovec iov = {
! 279: .iov_base = buf,
! 280: .iov_len = sizeof buf
! 281: };
1.1 misho 282: struct sockaddr_nl snl;
1.1.1.4 ! misho 283: struct msghdr msg = {
! 284: .msg_name = (void *) &snl,
! 285: .msg_namelen = sizeof snl,
! 286: .msg_iov = &iov,
! 287: .msg_iovlen = 1
! 288: };
1.1 misho 289: struct nlmsghdr *h;
290:
291: status = recvmsg (nl->sock, &msg, 0);
292: if (status < 0)
293: {
294: if (errno == EINTR)
295: continue;
296: if (errno == EWOULDBLOCK || errno == EAGAIN)
297: break;
298: zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
299: nl->name, safe_strerror(errno));
300: continue;
301: }
302:
303: if (status == 0)
304: {
305: zlog (NULL, LOG_ERR, "%s EOF", nl->name);
306: return -1;
307: }
308:
309: if (msg.msg_namelen != sizeof snl)
310: {
311: zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
312: nl->name, msg.msg_namelen);
313: return -1;
314: }
315:
316: for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
317: h = NLMSG_NEXT (h, status))
318: {
319: /* Finish of reading. */
320: if (h->nlmsg_type == NLMSG_DONE)
321: return ret;
322:
323: /* Error handling. */
324: if (h->nlmsg_type == NLMSG_ERROR)
325: {
326: struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
327: int errnum = err->error;
328: int msg_type = err->msg.nlmsg_type;
329:
330: /* If the error field is zero, then this is an ACK */
331: if (err->error == 0)
332: {
333: if (IS_ZEBRA_DEBUG_KERNEL)
334: {
335: zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
336: __FUNCTION__, nl->name,
337: lookup (nlmsg_str, err->msg.nlmsg_type),
338: err->msg.nlmsg_type, err->msg.nlmsg_seq,
339: err->msg.nlmsg_pid);
340: }
341:
342: /* return if not a multipart message, otherwise continue */
343: if (!(h->nlmsg_flags & NLM_F_MULTI))
344: {
345: return 0;
346: }
347: continue;
348: }
349:
350: if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
351: {
352: zlog (NULL, LOG_ERR, "%s error: message truncated",
353: nl->name);
354: return -1;
355: }
356:
357: /* Deal with errors that occur because of races in link handling */
1.1.1.4 ! misho 358: if (nl == &zvrf->netlink_cmd
1.1 misho 359: && ((msg_type == RTM_DELROUTE &&
360: (-errnum == ENODEV || -errnum == ESRCH))
361: || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
362: {
363: if (IS_ZEBRA_DEBUG_KERNEL)
364: zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
365: nl->name, safe_strerror (-errnum),
366: lookup (nlmsg_str, msg_type),
367: msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
368: return 0;
369: }
370:
371: zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
372: nl->name, safe_strerror (-errnum),
373: lookup (nlmsg_str, msg_type),
374: msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
375: return -1;
376: }
377:
378: /* OK we got netlink message. */
379: if (IS_ZEBRA_DEBUG_KERNEL)
380: zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
381: nl->name,
382: lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
383: h->nlmsg_seq, h->nlmsg_pid);
384:
1.1.1.4 ! misho 385: /* skip unsolicited messages originating from command socket
! 386: * linux sets the originators port-id for {NEW|DEL}ADDR messages,
! 387: * so this has to be checked here. */
! 388: if (nl != &zvrf->netlink_cmd
! 389: && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid
! 390: && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR))
1.1 misho 391: {
392: if (IS_ZEBRA_DEBUG_KERNEL)
393: zlog_debug ("netlink_parse_info: %s packet comes from %s",
1.1.1.4 ! misho 394: zvrf->netlink_cmd.name, nl->name);
1.1 misho 395: continue;
396: }
397:
1.1.1.4 ! misho 398: error = (*filter) (&snl, h, zvrf->vrf_id);
1.1 misho 399: if (error < 0)
400: {
401: zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
402: ret = error;
403: }
404: }
405:
406: /* After error care. */
407: if (msg.msg_flags & MSG_TRUNC)
408: {
409: zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
410: continue;
411: }
412: if (status)
413: {
414: zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
415: status);
416: return -1;
417: }
418: }
419: return ret;
420: }
421:
422: /* Utility function for parse rtattr. */
423: static void
424: netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
425: int len)
426: {
427: while (RTA_OK (rta, len))
428: {
429: if (rta->rta_type <= max)
430: tb[rta->rta_type] = rta;
431: rta = RTA_NEXT (rta, len);
432: }
433: }
434:
1.1.1.2 misho 435: /* Utility function to parse hardware link-layer address and update ifp */
436: static void
437: netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
438: {
439: int i;
440:
441: if (tb[IFLA_ADDRESS])
442: {
443: int hw_addr_len;
444:
445: hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
446:
447: if (hw_addr_len > INTERFACE_HWADDR_MAX)
448: zlog_warn ("Hardware address is too large: %d", hw_addr_len);
449: else
450: {
451: ifp->hw_addr_len = hw_addr_len;
452: memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
453:
454: for (i = 0; i < hw_addr_len; i++)
455: if (ifp->hw_addr[i] != 0)
456: break;
457:
458: if (i == hw_addr_len)
459: ifp->hw_addr_len = 0;
460: else
461: ifp->hw_addr_len = hw_addr_len;
462: }
463: }
464: }
465:
1.1.1.4 ! misho 466: static enum zebra_link_type
! 467: netlink_to_zebra_link_type (unsigned int hwt)
! 468: {
! 469: switch (hwt)
! 470: {
! 471: case ARPHRD_ETHER: return ZEBRA_LLT_ETHER;
! 472: case ARPHRD_EETHER: return ZEBRA_LLT_EETHER;
! 473: case ARPHRD_AX25: return ZEBRA_LLT_AX25;
! 474: case ARPHRD_PRONET: return ZEBRA_LLT_PRONET;
! 475: case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802;
! 476: case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET;
! 477: case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK;
! 478: case ARPHRD_DLCI: return ZEBRA_LLT_DLCI;
! 479: case ARPHRD_ATM: return ZEBRA_LLT_ATM;
! 480: case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM;
! 481: case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394;
! 482: case ARPHRD_EUI64: return ZEBRA_LLT_EUI64;
! 483: case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND;
! 484: case ARPHRD_SLIP: return ZEBRA_LLT_SLIP;
! 485: case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP;
! 486: case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6;
! 487: case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6;
! 488: case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD;
! 489: case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT;
! 490: case ARPHRD_ROSE: return ZEBRA_LLT_ROSE;
! 491: case ARPHRD_X25: return ZEBRA_LLT_X25;
! 492: case ARPHRD_PPP: return ZEBRA_LLT_PPP;
! 493: case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC;
! 494: case ARPHRD_LAPB: return ZEBRA_LLT_LAPB;
! 495: case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC;
! 496: case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP;
! 497: case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6;
! 498: case ARPHRD_FRAD: return ZEBRA_LLT_FRAD;
! 499: case ARPHRD_SKIP: return ZEBRA_LLT_SKIP;
! 500: case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK;
! 501: case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK;
! 502: case ARPHRD_FDDI: return ZEBRA_LLT_FDDI;
! 503: case ARPHRD_SIT: return ZEBRA_LLT_SIT;
! 504: case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP;
! 505: case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE;
! 506: case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG;
! 507: case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI;
! 508: case ARPHRD_ECONET: return ZEBRA_LLT_ECONET;
! 509: case ARPHRD_IRDA: return ZEBRA_LLT_IRDA;
! 510: case ARPHRD_FCPP: return ZEBRA_LLT_FCPP;
! 511: case ARPHRD_FCAL: return ZEBRA_LLT_FCAL;
! 512: case ARPHRD_FCPL: return ZEBRA_LLT_FCPL;
! 513: case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC;
! 514: case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR;
! 515: case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211;
! 516: case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154;
! 517: #ifdef ARPHRD_IP6GRE
! 518: case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE;
! 519: #endif
! 520: #ifdef ARPHRD_IEEE802154_PHY
! 521: case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY;
! 522: #endif
! 523:
! 524: default: return ZEBRA_LLT_UNKNOWN;
! 525: }
! 526: }
! 527:
1.1 misho 528: /* Called from interface_lookup_netlink(). This function is only used
529: during bootstrap. */
530: static int
1.1.1.4 ! misho 531: netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 532: vrf_id_t vrf_id)
1.1 misho 533: {
534: int len;
535: struct ifinfomsg *ifi;
536: struct rtattr *tb[IFLA_MAX + 1];
537: struct interface *ifp;
538: char *name;
539:
540: ifi = NLMSG_DATA (h);
541:
542: if (h->nlmsg_type != RTM_NEWLINK)
543: return 0;
544:
545: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
546: if (len < 0)
547: return -1;
548:
549: /* Looking up interface name. */
550: memset (tb, 0, sizeof tb);
551: netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
552:
553: #ifdef IFLA_WIRELESS
554: /* check for wireless messages to ignore */
555: if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
556: {
557: if (IS_ZEBRA_DEBUG_KERNEL)
558: zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
559: return 0;
560: }
561: #endif /* IFLA_WIRELESS */
562:
563: if (tb[IFLA_IFNAME] == NULL)
564: return -1;
565: name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
566:
567: /* Add interface. */
1.1.1.4 ! misho 568: ifp = if_get_by_name_vrf (name, vrf_id);
1.1 misho 569: set_ifindex(ifp, ifi->ifi_index);
570: ifp->flags = ifi->ifi_flags & 0x0000fffff;
571: ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
1.1.1.4 ! misho 572: ifp->metric = 0;
1.1 misho 573:
574: /* Hardware type and address. */
1.1.1.4 ! misho 575: ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type);
1.1.1.2 misho 576: netlink_interface_update_hw_addr (tb, ifp);
1.1 misho 577:
578: if_add_update (ifp);
579:
580: return 0;
581: }
582:
583: /* Lookup interface IPv4/IPv6 address. */
584: static int
1.1.1.4 ! misho 585: netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 586: vrf_id_t vrf_id)
1.1 misho 587: {
588: int len;
589: struct ifaddrmsg *ifa;
590: struct rtattr *tb[IFA_MAX + 1];
591: struct interface *ifp;
592: void *addr;
593: void *broad;
594: u_char flags = 0;
595: char *label = NULL;
596:
597: ifa = NLMSG_DATA (h);
598:
599: if (ifa->ifa_family != AF_INET
600: #ifdef HAVE_IPV6
601: && ifa->ifa_family != AF_INET6
602: #endif /* HAVE_IPV6 */
603: )
604: return 0;
605:
606: if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
607: return 0;
608:
609: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
610: if (len < 0)
611: return -1;
612:
613: memset (tb, 0, sizeof tb);
614: netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
615:
1.1.1.4 ! misho 616: ifp = if_lookup_by_index_vrf (ifa->ifa_index, vrf_id);
1.1 misho 617: if (ifp == NULL)
618: {
1.1.1.4 ! misho 619: zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u",
! 620: ifa->ifa_index, vrf_id);
1.1 misho 621: return -1;
622: }
623:
624: if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
625: {
626: char buf[BUFSIZ];
1.1.1.4 ! misho 627: zlog_debug ("netlink_interface_addr %s %s vrf %u:",
! 628: lookup (nlmsg_str, h->nlmsg_type), ifp->name, vrf_id);
1.1 misho 629: if (tb[IFA_LOCAL])
630: zlog_debug (" IFA_LOCAL %s/%d",
631: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
632: buf, BUFSIZ), ifa->ifa_prefixlen);
633: if (tb[IFA_ADDRESS])
634: zlog_debug (" IFA_ADDRESS %s/%d",
635: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
636: buf, BUFSIZ), ifa->ifa_prefixlen);
637: if (tb[IFA_BROADCAST])
638: zlog_debug (" IFA_BROADCAST %s/%d",
639: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
640: buf, BUFSIZ), ifa->ifa_prefixlen);
641: if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
642: zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
643:
644: if (tb[IFA_CACHEINFO])
645: {
646: struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
647: zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
648: ci->ifa_prefered, ci->ifa_valid);
649: }
650: }
651:
652: /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
653: if (tb[IFA_LOCAL] == NULL)
654: tb[IFA_LOCAL] = tb[IFA_ADDRESS];
655: if (tb[IFA_ADDRESS] == NULL)
656: tb[IFA_ADDRESS] = tb[IFA_LOCAL];
657:
658: /* local interface address */
659: addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
660:
661: /* is there a peer address? */
662: if (tb[IFA_ADDRESS] &&
663: memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
664: {
665: broad = RTA_DATA(tb[IFA_ADDRESS]);
666: SET_FLAG (flags, ZEBRA_IFA_PEER);
667: }
668: else
669: /* seeking a broadcast address */
670: broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
671:
672: /* addr is primary key, SOL if we don't have one */
673: if (addr == NULL)
674: {
675: zlog_debug ("%s: NULL address", __func__);
676: return -1;
677: }
678:
679: /* Flags. */
680: if (ifa->ifa_flags & IFA_F_SECONDARY)
681: SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
682:
683: /* Label */
684: if (tb[IFA_LABEL])
685: label = (char *) RTA_DATA (tb[IFA_LABEL]);
686:
687: if (ifp && label && strcmp (ifp->name, label) == 0)
688: label = NULL;
689:
690: /* Register interface address to the interface. */
691: if (ifa->ifa_family == AF_INET)
692: {
693: if (h->nlmsg_type == RTM_NEWADDR)
694: connected_add_ipv4 (ifp, flags,
695: (struct in_addr *) addr, ifa->ifa_prefixlen,
696: (struct in_addr *) broad, label);
697: else
698: connected_delete_ipv4 (ifp, flags,
699: (struct in_addr *) addr, ifa->ifa_prefixlen,
700: (struct in_addr *) broad);
701: }
702: #ifdef HAVE_IPV6
703: if (ifa->ifa_family == AF_INET6)
704: {
705: if (h->nlmsg_type == RTM_NEWADDR)
706: connected_add_ipv6 (ifp, flags,
707: (struct in6_addr *) addr, ifa->ifa_prefixlen,
708: (struct in6_addr *) broad, label);
709: else
710: connected_delete_ipv6 (ifp,
711: (struct in6_addr *) addr, ifa->ifa_prefixlen,
712: (struct in6_addr *) broad);
713: }
714: #endif /* HAVE_IPV6 */
715:
716: return 0;
717: }
718:
719: /* Looking up routing table by netlink interface. */
720: static int
1.1.1.4 ! misho 721: netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 722: vrf_id_t vrf_id)
1.1 misho 723: {
724: int len;
725: struct rtmsg *rtm;
726: struct rtattr *tb[RTA_MAX + 1];
727: u_char flags = 0;
728:
729: char anyaddr[16] = { 0 };
730:
731: int index;
732: int table;
1.1.1.4 ! misho 733: u_int32_t mtu = 0;
1.1 misho 734:
735: void *dest;
736: void *gate;
737: void *src;
738:
739: rtm = NLMSG_DATA (h);
740:
741: if (h->nlmsg_type != RTM_NEWROUTE)
742: return 0;
743: if (rtm->rtm_type != RTN_UNICAST)
744: return 0;
745:
746: table = rtm->rtm_table;
747: #if 0 /* we weed them out later in rib_weed_tables () */
748: if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
749: return 0;
750: #endif
751:
752: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
753: if (len < 0)
754: return -1;
755:
756: memset (tb, 0, sizeof tb);
757: netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
758:
759: if (rtm->rtm_flags & RTM_F_CLONED)
760: return 0;
761: if (rtm->rtm_protocol == RTPROT_REDIRECT)
762: return 0;
763: if (rtm->rtm_protocol == RTPROT_KERNEL)
764: return 0;
765:
766: if (rtm->rtm_src_len != 0)
767: return 0;
768:
769: /* Route which inserted by Zebra. */
770: if (rtm->rtm_protocol == RTPROT_ZEBRA)
771: flags |= ZEBRA_FLAG_SELFROUTE;
772:
773: index = 0;
774: dest = NULL;
775: gate = NULL;
776: src = NULL;
777:
778: if (tb[RTA_OIF])
779: index = *(int *) RTA_DATA (tb[RTA_OIF]);
780:
781: if (tb[RTA_DST])
782: dest = RTA_DATA (tb[RTA_DST]);
783: else
784: dest = anyaddr;
785:
786: if (tb[RTA_PREFSRC])
787: src = RTA_DATA (tb[RTA_PREFSRC]);
788:
789: if (tb[RTA_GATEWAY])
790: gate = RTA_DATA (tb[RTA_GATEWAY]);
791:
1.1.1.4 ! misho 792: if (tb[RTA_METRICS])
! 793: {
! 794: struct rtattr *mxrta[RTAX_MAX+1];
! 795:
! 796: memset (mxrta, 0, sizeof mxrta);
! 797: netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
! 798: RTA_PAYLOAD(tb[RTA_METRICS]));
! 799:
! 800: if (mxrta[RTAX_MTU])
! 801: mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
! 802: }
1.1 misho 803:
804: if (rtm->rtm_family == AF_INET)
805: {
806: struct prefix_ipv4 p;
807: p.family = AF_INET;
808: memcpy (&p.prefix, dest, 4);
809: p.prefixlen = rtm->rtm_dst_len;
810:
1.1.1.2 misho 811: if (!tb[RTA_MULTIPATH])
812: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
1.1.1.4 ! misho 813: vrf_id, table, 0, mtu, 0, SAFI_UNICAST);
1.1.1.2 misho 814: else
815: {
816: /* This is a multipath route */
817:
818: struct rib *rib;
819: struct rtnexthop *rtnh =
820: (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
821:
822: len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
823:
824: rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
825: rib->type = ZEBRA_ROUTE_KERNEL;
826: rib->distance = 0;
827: rib->flags = flags;
1.1.1.4 ! misho 828: rib->metric = 0;
! 829: rib->mtu = mtu;
! 830: rib->vrf_id = vrf_id;
1.1.1.2 misho 831: rib->table = table;
832: rib->nexthop_num = 0;
833: rib->uptime = time (NULL);
834:
835: for (;;)
836: {
837: if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
838: break;
839:
840: index = rtnh->rtnh_ifindex;
841: gate = 0;
842: if (rtnh->rtnh_len > sizeof (*rtnh))
843: {
844: memset (tb, 0, sizeof (tb));
845: netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
846: rtnh->rtnh_len - sizeof (*rtnh));
847: if (tb[RTA_GATEWAY])
848: gate = RTA_DATA (tb[RTA_GATEWAY]);
849: }
850:
851: if (gate)
852: {
853: if (index)
854: nexthop_ipv4_ifindex_add (rib, gate, src, index);
855: else
856: nexthop_ipv4_add (rib, gate, src);
857: }
858: else
859: nexthop_ifindex_add (rib, index);
860:
861: len -= NLMSG_ALIGN(rtnh->rtnh_len);
862: rtnh = RTNH_NEXT(rtnh);
863: }
864:
865: if (rib->nexthop_num == 0)
866: XFREE (MTYPE_RIB, rib);
867: else
868: rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
869: }
1.1 misho 870: }
871: #ifdef HAVE_IPV6
872: if (rtm->rtm_family == AF_INET6)
873: {
874: struct prefix_ipv6 p;
875: p.family = AF_INET6;
876: memcpy (&p.prefix, dest, 16);
877: p.prefixlen = rtm->rtm_dst_len;
878:
1.1.1.4 ! misho 879: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id,
! 880: table, 0, mtu, 0, SAFI_UNICAST);
1.1 misho 881: }
882: #endif /* HAVE_IPV6 */
883:
884: return 0;
885: }
886:
887: static const struct message rtproto_str[] = {
888: {RTPROT_REDIRECT, "redirect"},
889: {RTPROT_KERNEL, "kernel"},
890: {RTPROT_BOOT, "boot"},
891: {RTPROT_STATIC, "static"},
892: {RTPROT_GATED, "GateD"},
893: {RTPROT_RA, "router advertisement"},
894: {RTPROT_MRT, "MRT"},
895: {RTPROT_ZEBRA, "Zebra"},
896: #ifdef RTPROT_BIRD
897: {RTPROT_BIRD, "BIRD"},
898: #endif /* RTPROT_BIRD */
899: {0, NULL}
900: };
901:
902: /* Routing information change from the kernel. */
903: static int
1.1.1.4 ! misho 904: netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 905: vrf_id_t vrf_id)
1.1 misho 906: {
907: int len;
908: struct rtmsg *rtm;
909: struct rtattr *tb[RTA_MAX + 1];
910:
911: char anyaddr[16] = { 0 };
912:
913: int index;
914: int table;
1.1.1.4 ! misho 915: u_int32_t mtu = 0;
1.1 misho 916:
917: void *dest;
918: void *gate;
919: void *src;
920:
921: rtm = NLMSG_DATA (h);
922:
923: if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
924: {
925: /* If this is not route add/delete message print warning. */
1.1.1.4 ! misho 926: zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id);
1.1 misho 927: return 0;
928: }
929:
930: /* Connected route. */
931: if (IS_ZEBRA_DEBUG_KERNEL)
1.1.1.4 ! misho 932: zlog_debug ("%s %s %s proto %s vrf %u",
1.1 misho 933: h->nlmsg_type ==
934: RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
935: rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
936: rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
1.1.1.4 ! misho 937: lookup (rtproto_str, rtm->rtm_protocol),
! 938: vrf_id);
1.1 misho 939:
940: if (rtm->rtm_type != RTN_UNICAST)
941: {
942: return 0;
943: }
944:
945: table = rtm->rtm_table;
946: if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
947: {
948: return 0;
949: }
950:
951: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
952: if (len < 0)
953: return -1;
954:
955: memset (tb, 0, sizeof tb);
956: netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
957:
958: if (rtm->rtm_flags & RTM_F_CLONED)
959: return 0;
960: if (rtm->rtm_protocol == RTPROT_REDIRECT)
961: return 0;
962: if (rtm->rtm_protocol == RTPROT_KERNEL)
963: return 0;
964:
965: if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
966: return 0;
967:
968: if (rtm->rtm_src_len != 0)
969: {
1.1.1.4 ! misho 970: zlog_warn ("netlink_route_change(): no src len, vrf %u", vrf_id);
1.1 misho 971: return 0;
972: }
973:
974: index = 0;
975: dest = NULL;
976: gate = NULL;
977: src = NULL;
978:
979: if (tb[RTA_OIF])
980: index = *(int *) RTA_DATA (tb[RTA_OIF]);
981:
982: if (tb[RTA_DST])
983: dest = RTA_DATA (tb[RTA_DST]);
984: else
985: dest = anyaddr;
986:
987: if (tb[RTA_GATEWAY])
988: gate = RTA_DATA (tb[RTA_GATEWAY]);
989:
990: if (tb[RTA_PREFSRC])
991: src = RTA_DATA (tb[RTA_PREFSRC]);
992:
1.1.1.4 ! misho 993: if (h->nlmsg_type == RTM_NEWROUTE)
! 994: {
! 995: if (tb[RTA_METRICS])
! 996: {
! 997: struct rtattr *mxrta[RTAX_MAX+1];
! 998:
! 999: memset (mxrta, 0, sizeof mxrta);
! 1000: netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
! 1001: RTA_PAYLOAD(tb[RTA_METRICS]));
! 1002:
! 1003: if (mxrta[RTAX_MTU])
! 1004: mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
! 1005: }
! 1006: }
1.1 misho 1007:
1008: if (rtm->rtm_family == AF_INET)
1009: {
1010: struct prefix_ipv4 p;
1011: p.family = AF_INET;
1012: memcpy (&p.prefix, dest, 4);
1013: p.prefixlen = rtm->rtm_dst_len;
1014:
1015: if (IS_ZEBRA_DEBUG_KERNEL)
1016: {
1.1.1.4 ! misho 1017: char buf[PREFIX_STRLEN];
! 1018: zlog_debug ("%s %s vrf %u",
! 1019: h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
! 1020: prefix2str (&p, buf, sizeof(buf)), vrf_id);
1.1 misho 1021: }
1022:
1023: if (h->nlmsg_type == RTM_NEWROUTE)
1.1.1.2 misho 1024: {
1025: if (!tb[RTA_MULTIPATH])
1.1.1.4 ! misho 1026: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id,
! 1027: table, 0, mtu, 0, SAFI_UNICAST);
1.1.1.2 misho 1028: else
1029: {
1030: /* This is a multipath route */
1031:
1032: struct rib *rib;
1033: struct rtnexthop *rtnh =
1034: (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
1035:
1036: len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
1037:
1038: rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
1039: rib->type = ZEBRA_ROUTE_KERNEL;
1040: rib->distance = 0;
1041: rib->flags = 0;
1.1.1.4 ! misho 1042: rib->metric = 0;
! 1043: rib->mtu = mtu;
! 1044: rib->vrf_id = vrf_id;
1.1.1.2 misho 1045: rib->table = table;
1046: rib->nexthop_num = 0;
1047: rib->uptime = time (NULL);
1048:
1049: for (;;)
1050: {
1051: if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
1052: break;
1053:
1054: index = rtnh->rtnh_ifindex;
1055: gate = 0;
1056: if (rtnh->rtnh_len > sizeof (*rtnh))
1057: {
1058: memset (tb, 0, sizeof (tb));
1059: netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
1060: rtnh->rtnh_len - sizeof (*rtnh));
1061: if (tb[RTA_GATEWAY])
1062: gate = RTA_DATA (tb[RTA_GATEWAY]);
1063: }
1064:
1065: if (gate)
1066: {
1067: if (index)
1068: nexthop_ipv4_ifindex_add (rib, gate, src, index);
1069: else
1070: nexthop_ipv4_add (rib, gate, src);
1071: }
1072: else
1073: nexthop_ifindex_add (rib, index);
1074:
1075: len -= NLMSG_ALIGN(rtnh->rtnh_len);
1076: rtnh = RTNH_NEXT(rtnh);
1077: }
1078:
1079: if (rib->nexthop_num == 0)
1080: XFREE (MTYPE_RIB, rib);
1081: else
1082: rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
1083: }
1084: }
1.1 misho 1085: else
1.1.1.4 ! misho 1086: rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
! 1087: SAFI_UNICAST);
1.1 misho 1088: }
1089:
1090: #ifdef HAVE_IPV6
1091: if (rtm->rtm_family == AF_INET6)
1092: {
1093: struct prefix_ipv6 p;
1094:
1095: p.family = AF_INET6;
1096: memcpy (&p.prefix, dest, 16);
1097: p.prefixlen = rtm->rtm_dst_len;
1098:
1099: if (IS_ZEBRA_DEBUG_KERNEL)
1100: {
1.1.1.4 ! misho 1101: char buf[PREFIX_STRLEN];
! 1102: zlog_debug ("%s %s vrf %u",
! 1103: h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
! 1104: prefix2str (&p, buf, sizeof(buf)), vrf_id);
1.1 misho 1105: }
1106:
1107: if (h->nlmsg_type == RTM_NEWROUTE)
1.1.1.4 ! misho 1108: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table,
! 1109: 0, mtu, 0, SAFI_UNICAST);
1.1 misho 1110: else
1.1.1.4 ! misho 1111: rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
! 1112: SAFI_UNICAST);
1.1 misho 1113: }
1114: #endif /* HAVE_IPV6 */
1115:
1116: return 0;
1117: }
1118:
1119: static int
1.1.1.4 ! misho 1120: netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 1121: vrf_id_t vrf_id)
1.1 misho 1122: {
1123: int len;
1124: struct ifinfomsg *ifi;
1125: struct rtattr *tb[IFLA_MAX + 1];
1126: struct interface *ifp;
1127: char *name;
1128:
1129: ifi = NLMSG_DATA (h);
1130:
1131: if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
1132: {
1133: /* If this is not link add/delete message so print warning. */
1.1.1.4 ! misho 1134: zlog_warn ("netlink_link_change: wrong kernel message %d vrf %u\n",
! 1135: h->nlmsg_type, vrf_id);
1.1 misho 1136: return 0;
1137: }
1138:
1139: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
1140: if (len < 0)
1141: return -1;
1142:
1143: /* Looking up interface name. */
1144: memset (tb, 0, sizeof tb);
1145: netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
1146:
1147: #ifdef IFLA_WIRELESS
1148: /* check for wireless messages to ignore */
1149: if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
1150: {
1151: if (IS_ZEBRA_DEBUG_KERNEL)
1.1.1.4 ! misho 1152: zlog_debug ("%s: ignoring IFLA_WIRELESS message, vrf %u", __func__,
! 1153: vrf_id);
1.1 misho 1154: return 0;
1155: }
1156: #endif /* IFLA_WIRELESS */
1157:
1158: if (tb[IFLA_IFNAME] == NULL)
1159: return -1;
1160: name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
1161:
1162: /* Add interface. */
1163: if (h->nlmsg_type == RTM_NEWLINK)
1164: {
1.1.1.4 ! misho 1165: ifp = if_lookup_by_name_vrf (name, vrf_id);
1.1 misho 1166:
1167: if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1168: {
1169: if (ifp == NULL)
1.1.1.4 ! misho 1170: ifp = if_get_by_name_vrf (name, vrf_id);
1.1 misho 1171:
1172: set_ifindex(ifp, ifi->ifi_index);
1173: ifp->flags = ifi->ifi_flags & 0x0000fffff;
1174: ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
1.1.1.4 ! misho 1175: ifp->metric = 0;
1.1 misho 1176:
1.1.1.2 misho 1177: netlink_interface_update_hw_addr (tb, ifp);
1178:
1.1 misho 1179: /* If new link is added. */
1180: if_add_update (ifp);
1181: }
1182: else
1183: {
1184: /* Interface status change. */
1185: set_ifindex(ifp, ifi->ifi_index);
1186: ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
1.1.1.4 ! misho 1187: ifp->metric = 0;
1.1 misho 1188:
1.1.1.2 misho 1189: netlink_interface_update_hw_addr (tb, ifp);
1190:
1.1 misho 1191: if (if_is_operative (ifp))
1192: {
1193: ifp->flags = ifi->ifi_flags & 0x0000fffff;
1194: if (!if_is_operative (ifp))
1195: if_down (ifp);
1196: else
1197: /* Must notify client daemons of new interface status. */
1198: zebra_interface_up_update (ifp);
1199: }
1200: else
1201: {
1202: ifp->flags = ifi->ifi_flags & 0x0000fffff;
1203: if (if_is_operative (ifp))
1204: if_up (ifp);
1205: }
1206: }
1207: }
1208: else
1209: {
1210: /* RTM_DELLINK. */
1.1.1.4 ! misho 1211: ifp = if_lookup_by_name_vrf (name, vrf_id);
1.1 misho 1212:
1213: if (ifp == NULL)
1214: {
1.1.1.4 ! misho 1215: zlog_warn ("interface %s vrf %u is deleted but can't find",
! 1216: name, vrf_id);
1.1 misho 1217: return 0;
1218: }
1219:
1220: if_delete_update (ifp);
1221: }
1222:
1223: return 0;
1224: }
1225:
1226: static int
1.1.1.4 ! misho 1227: netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 1228: vrf_id_t vrf_id)
1.1 misho 1229: {
1230: /* JF: Ignore messages that aren't from the kernel */
1231: if ( snl->nl_pid != 0 )
1232: {
1233: zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1234: return 0;
1235: }
1236:
1237: switch (h->nlmsg_type)
1238: {
1239: case RTM_NEWROUTE:
1.1.1.4 ! misho 1240: return netlink_route_change (snl, h, vrf_id);
1.1 misho 1241: break;
1242: case RTM_DELROUTE:
1.1.1.4 ! misho 1243: return netlink_route_change (snl, h, vrf_id);
1.1 misho 1244: break;
1245: case RTM_NEWLINK:
1.1.1.4 ! misho 1246: return netlink_link_change (snl, h, vrf_id);
1.1 misho 1247: break;
1248: case RTM_DELLINK:
1.1.1.4 ! misho 1249: return netlink_link_change (snl, h, vrf_id);
1.1 misho 1250: break;
1251: case RTM_NEWADDR:
1.1.1.4 ! misho 1252: return netlink_interface_addr (snl, h, vrf_id);
1.1 misho 1253: break;
1254: case RTM_DELADDR:
1.1.1.4 ! misho 1255: return netlink_interface_addr (snl, h, vrf_id);
1.1 misho 1256: break;
1257: default:
1.1.1.4 ! misho 1258: zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
! 1259: vrf_id);
1.1 misho 1260: break;
1261: }
1262: return 0;
1263: }
1264:
1265: /* Interface lookup by netlink socket. */
1266: int
1.1.1.4 ! misho 1267: interface_lookup_netlink (struct zebra_vrf *zvrf)
1.1 misho 1268: {
1269: int ret;
1270:
1271: /* Get interface information. */
1.1.1.4 ! misho 1272: ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd);
1.1 misho 1273: if (ret < 0)
1274: return ret;
1.1.1.4 ! misho 1275: ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf);
1.1 misho 1276: if (ret < 0)
1277: return ret;
1278:
1279: /* Get IPv4 address of the interfaces. */
1.1.1.4 ! misho 1280: ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd);
1.1 misho 1281: if (ret < 0)
1282: return ret;
1.1.1.4 ! misho 1283: ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
1.1 misho 1284: if (ret < 0)
1285: return ret;
1286:
1287: #ifdef HAVE_IPV6
1288: /* Get IPv6 address of the interfaces. */
1.1.1.4 ! misho 1289: ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd);
1.1 misho 1290: if (ret < 0)
1291: return ret;
1.1.1.4 ! misho 1292: ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
1.1 misho 1293: if (ret < 0)
1294: return ret;
1295: #endif /* HAVE_IPV6 */
1296:
1297: return 0;
1298: }
1299:
1300: /* Routing table read function using netlink interface. Only called
1301: bootstrap time. */
1302: int
1.1.1.4 ! misho 1303: netlink_route_read (struct zebra_vrf *zvrf)
1.1 misho 1304: {
1305: int ret;
1306:
1307: /* Get IPv4 routing table. */
1.1.1.4 ! misho 1308: ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd);
1.1 misho 1309: if (ret < 0)
1310: return ret;
1.1.1.4 ! misho 1311: ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
1.1 misho 1312: if (ret < 0)
1313: return ret;
1314:
1315: #ifdef HAVE_IPV6
1316: /* Get IPv6 routing table. */
1.1.1.4 ! misho 1317: ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd);
1.1 misho 1318: if (ret < 0)
1319: return ret;
1.1.1.4 ! misho 1320: ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
1.1 misho 1321: if (ret < 0)
1322: return ret;
1323: #endif /* HAVE_IPV6 */
1324:
1325: return 0;
1326: }
1327:
1328: /* Utility function comes from iproute2.
1329: Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1.1.1.3 misho 1330: int
1.1.1.4 ! misho 1331: addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen)
1.1 misho 1332: {
1.1.1.4 ! misho 1333: size_t len;
1.1 misho 1334: struct rtattr *rta;
1335:
1336: len = RTA_LENGTH (alen);
1337:
1338: if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1339: return -1;
1340:
1341: rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
1342: rta->rta_type = type;
1343: rta->rta_len = len;
1344: memcpy (RTA_DATA (rta), data, alen);
1345: n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1346:
1347: return 0;
1348: }
1349:
1.1.1.3 misho 1350: int
1.1 misho 1351: rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1352: {
1353: int len;
1354: struct rtattr *subrta;
1355:
1356: len = RTA_LENGTH (alen);
1357:
1358: if (RTA_ALIGN (rta->rta_len) + len > maxlen)
1359: return -1;
1360:
1361: subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
1362: subrta->rta_type = type;
1363: subrta->rta_len = len;
1364: memcpy (RTA_DATA (subrta), data, alen);
1365: rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1366:
1367: return 0;
1368: }
1369:
1370: /* Utility function comes from iproute2.
1371: Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1.1.1.3 misho 1372: int
1.1.1.4 ! misho 1373: addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data)
1.1 misho 1374: {
1.1.1.4 ! misho 1375: size_t len;
1.1 misho 1376: struct rtattr *rta;
1377:
1378: len = RTA_LENGTH (4);
1379:
1380: if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1381: return -1;
1382:
1383: rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
1384: rta->rta_type = type;
1385: rta->rta_len = len;
1386: memcpy (RTA_DATA (rta), &data, 4);
1387: n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1388:
1389: return 0;
1390: }
1391:
1392: static int
1.1.1.4 ! misho 1393: netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
! 1394: vrf_id_t vrf_id)
1.1 misho 1395: {
1.1.1.4 ! misho 1396: zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type,
! 1397: vrf_id);
1.1 misho 1398: return 0;
1399: }
1400:
1401: /* sendmsg() to netlink socket then recvmsg(). */
1402: static int
1.1.1.4 ! misho 1403: netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf)
1.1 misho 1404: {
1405: int status;
1406: struct sockaddr_nl snl;
1.1.1.4 ! misho 1407: struct iovec iov = {
! 1408: .iov_base = (void *) n,
! 1409: .iov_len = n->nlmsg_len
! 1410: };
! 1411: struct msghdr msg = {
! 1412: .msg_name = (void *) &snl,
! 1413: .msg_namelen = sizeof snl,
! 1414: .msg_iov = &iov,
! 1415: .msg_iovlen = 1,
! 1416: };
1.1 misho 1417: int save_errno;
1418:
1419: memset (&snl, 0, sizeof snl);
1420: snl.nl_family = AF_NETLINK;
1421:
1422: n->nlmsg_seq = ++nl->seq;
1423:
1424: /* Request an acknowledgement by setting NLM_F_ACK */
1425: n->nlmsg_flags |= NLM_F_ACK;
1426:
1427: if (IS_ZEBRA_DEBUG_KERNEL)
1428: zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
1429: lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1430: n->nlmsg_seq);
1431:
1432: /* Send message to netlink interface. */
1433: if (zserv_privs.change (ZPRIVS_RAISE))
1434: zlog (NULL, LOG_ERR, "Can't raise privileges");
1435: status = sendmsg (nl->sock, &msg, 0);
1436: save_errno = errno;
1437: if (zserv_privs.change (ZPRIVS_LOWER))
1438: zlog (NULL, LOG_ERR, "Can't lower privileges");
1439:
1440: if (status < 0)
1441: {
1442: zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
1443: safe_strerror (save_errno));
1444: return -1;
1445: }
1446:
1447:
1448: /*
1449: * Get reply from netlink socket.
1450: * The reply should either be an acknowlegement or an error.
1451: */
1.1.1.4 ! misho 1452: return netlink_parse_info (netlink_talk_filter, nl, zvrf);
1.1 misho 1453: }
1454:
1.1.1.4 ! misho 1455: /* This function takes a nexthop as argument and adds
! 1456: * the appropriate netlink attributes to an existing
! 1457: * netlink message.
! 1458: *
! 1459: * @param routedesc: Human readable description of route type
! 1460: * (direct/recursive, single-/multipath)
! 1461: * @param bytelen: Length of addresses in bytes.
! 1462: * @param nexthop: Nexthop information
! 1463: * @param nlmsg: nlmsghdr structure to fill in.
! 1464: * @param req_size: The size allocated for the message.
! 1465: */
! 1466: static void
! 1467: _netlink_route_build_singlepath(
! 1468: const char *routedesc,
! 1469: int bytelen,
! 1470: struct nexthop *nexthop,
! 1471: struct nlmsghdr *nlmsg,
! 1472: struct rtmsg *rtmsg,
! 1473: size_t req_size)
! 1474: {
! 1475: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
! 1476: rtmsg->rtm_flags |= RTNH_F_ONLINK;
! 1477: if (nexthop->type == NEXTHOP_TYPE_IPV4
! 1478: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1479: {
! 1480: addattr_l (nlmsg, req_size, RTA_GATEWAY,
! 1481: &nexthop->gate.ipv4, bytelen);
! 1482: if (nexthop->src.ipv4.s_addr)
! 1483: addattr_l (nlmsg, req_size, RTA_PREFSRC,
! 1484: &nexthop->src.ipv4, bytelen);
1.1 misho 1485:
1.1.1.4 ! misho 1486: if (IS_ZEBRA_DEBUG_KERNEL)
! 1487: zlog_debug("netlink_route_multipath() (%s): "
! 1488: "nexthop via %s if %u",
! 1489: routedesc,
! 1490: inet_ntoa (nexthop->gate.ipv4),
! 1491: nexthop->ifindex);
! 1492: }
! 1493: #ifdef HAVE_IPV6
! 1494: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 1495: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 1496: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1497: {
! 1498: addattr_l (nlmsg, req_size, RTA_GATEWAY,
! 1499: &nexthop->gate.ipv6, bytelen);
1.1 misho 1500:
1.1.1.4 ! misho 1501: if (IS_ZEBRA_DEBUG_KERNEL)
! 1502: zlog_debug("netlink_route_multipath() (%s): "
! 1503: "nexthop via %s if %u",
! 1504: routedesc,
! 1505: inet6_ntoa (nexthop->gate.ipv6),
! 1506: nexthop->ifindex);
! 1507: }
! 1508: #endif /* HAVE_IPV6 */
! 1509: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
! 1510: || nexthop->type == NEXTHOP_TYPE_IFNAME
! 1511: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1512: {
! 1513: addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
! 1514:
! 1515: if (nexthop->src.ipv4.s_addr)
! 1516: addattr_l (nlmsg, req_size, RTA_PREFSRC,
! 1517: &nexthop->src.ipv4, bytelen);
1.1 misho 1518:
1.1.1.4 ! misho 1519: if (IS_ZEBRA_DEBUG_KERNEL)
! 1520: zlog_debug("netlink_route_multipath() (%s): "
! 1521: "nexthop via if %u", routedesc, nexthop->ifindex);
! 1522: }
1.1 misho 1523:
1.1.1.4 ! misho 1524: if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
! 1525: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1.1 misho 1526: {
1.1.1.4 ! misho 1527: addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
! 1528:
! 1529: if (IS_ZEBRA_DEBUG_KERNEL)
! 1530: zlog_debug("netlink_route_multipath() (%s): "
! 1531: "nexthop via if %u", routedesc, nexthop->ifindex);
1.1 misho 1532: }
1.1.1.4 ! misho 1533: }
1.1 misho 1534:
1.1.1.4 ! misho 1535: /* This function takes a nexthop as argument and
! 1536: * appends to the given rtattr/rtnexthop pair the
! 1537: * representation of the nexthop. If the nexthop
! 1538: * defines a preferred source, the src parameter
! 1539: * will be modified to point to that src, otherwise
! 1540: * it will be kept unmodified.
! 1541: *
! 1542: * @param routedesc: Human readable description of route type
! 1543: * (direct/recursive, single-/multipath)
! 1544: * @param bytelen: Length of addresses in bytes.
! 1545: * @param nexthop: Nexthop information
! 1546: * @param rta: rtnetlink attribute structure
! 1547: * @param rtnh: pointer to an rtnetlink nexthop structure
! 1548: * @param src: pointer pointing to a location where
! 1549: * the prefsrc should be stored.
! 1550: */
! 1551: static void
! 1552: _netlink_route_build_multipath(
! 1553: const char *routedesc,
! 1554: int bytelen,
! 1555: struct nexthop *nexthop,
! 1556: struct rtattr *rta,
! 1557: struct rtnexthop *rtnh,
! 1558: union g_addr **src
! 1559: )
! 1560: {
! 1561: rtnh->rtnh_len = sizeof (*rtnh);
! 1562: rtnh->rtnh_flags = 0;
! 1563: rtnh->rtnh_hops = 0;
! 1564: rta->rta_len += rtnh->rtnh_len;
! 1565:
! 1566: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
! 1567: rtnh->rtnh_flags |= RTNH_F_ONLINK;
! 1568:
! 1569: if (nexthop->type == NEXTHOP_TYPE_IPV4
! 1570: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1571: {
! 1572: rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
! 1573: &nexthop->gate.ipv4, bytelen);
! 1574: rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
1.1 misho 1575:
1.1.1.4 ! misho 1576: if (nexthop->src.ipv4.s_addr)
! 1577: *src = &nexthop->src;
! 1578:
! 1579: if (IS_ZEBRA_DEBUG_KERNEL)
! 1580: zlog_debug("netlink_route_multipath() (%s): "
! 1581: "nexthop via %s if %u",
! 1582: routedesc,
! 1583: inet_ntoa (nexthop->gate.ipv4),
! 1584: nexthop->ifindex);
1.1 misho 1585: }
1.1.1.4 ! misho 1586: #ifdef HAVE_IPV6
! 1587: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 1588: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 1589: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1590: {
! 1591: rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
! 1592: &nexthop->gate.ipv6, bytelen);
! 1593: rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
1.1 misho 1594:
1.1.1.4 ! misho 1595: if (IS_ZEBRA_DEBUG_KERNEL)
! 1596: zlog_debug("netlink_route_multipath() (%s): "
! 1597: "nexthop via %s if %u",
! 1598: routedesc,
! 1599: inet6_ntoa (nexthop->gate.ipv6),
! 1600: nexthop->ifindex);
! 1601: }
! 1602: #endif /* HAVE_IPV6 */
! 1603: /* ifindex */
! 1604: if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
! 1605: || nexthop->type == NEXTHOP_TYPE_IFINDEX
! 1606: || nexthop->type == NEXTHOP_TYPE_IFNAME)
! 1607: {
! 1608: rtnh->rtnh_ifindex = nexthop->ifindex;
! 1609: if (nexthop->src.ipv4.s_addr)
! 1610: *src = &nexthop->src;
! 1611: if (IS_ZEBRA_DEBUG_KERNEL)
! 1612: zlog_debug("netlink_route_multipath() (%s): "
! 1613: "nexthop via if %u", routedesc, nexthop->ifindex);
! 1614: }
! 1615: else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 1616: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1617: {
! 1618: rtnh->rtnh_ifindex = nexthop->ifindex;
1.1 misho 1619:
1.1.1.4 ! misho 1620: if (IS_ZEBRA_DEBUG_KERNEL)
! 1621: zlog_debug("netlink_route_multipath() (%s): "
! 1622: "nexthop via if %u", routedesc, nexthop->ifindex);
! 1623: }
! 1624: else
! 1625: {
! 1626: rtnh->rtnh_ifindex = 0;
! 1627: }
! 1628: }
1.1 misho 1629:
1.1.1.4 ! misho 1630: /* Log debug information for netlink_route_multipath
! 1631: * if debug logging is enabled.
! 1632: *
! 1633: * @param cmd: Netlink command which is to be processed
! 1634: * @param p: Prefix for which the change is due
! 1635: * @param nexthop: Nexthop which is currently processed
! 1636: * @param routedesc: Semantic annotation for nexthop
! 1637: * (recursive, multipath, etc.)
! 1638: * @param family: Address family which the change concerns
! 1639: */
! 1640: static void
! 1641: _netlink_route_debug(
! 1642: int cmd,
! 1643: struct prefix *p,
! 1644: struct nexthop *nexthop,
! 1645: const char *routedesc,
! 1646: int family,
! 1647: struct zebra_vrf *zvrf)
! 1648: {
! 1649: if (IS_ZEBRA_DEBUG_KERNEL)
! 1650: {
! 1651: char buf[PREFIX_STRLEN];
! 1652: zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s",
! 1653: routedesc,
! 1654: lookup (nlmsg_str, cmd),
! 1655: prefix2str (p, buf, sizeof(buf)),
! 1656: zvrf->vrf_id,
! 1657: nexthop_type_to_str (nexthop->type));
! 1658: }
1.1 misho 1659: }
1660:
1661: /* Routing table change via netlink interface. */
1662: static int
1.1.1.4 ! misho 1663: netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
1.1 misho 1664: {
1665: int bytelen;
1666: struct sockaddr_nl snl;
1.1.1.4 ! misho 1667: struct nexthop *nexthop = NULL, *tnexthop;
! 1668: int recursing;
! 1669: int nexthop_num;
1.1 misho 1670: int discard;
1.1.1.4 ! misho 1671: int family = PREFIX_FAMILY(p);
! 1672: const char *routedesc;
1.1 misho 1673:
1674: struct
1675: {
1676: struct nlmsghdr n;
1677: struct rtmsg r;
1.1.1.2 misho 1678: char buf[NL_PKT_BUF_SIZE];
1.1 misho 1679: } req;
1680:
1.1.1.4 ! misho 1681: struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id);
! 1682:
1.1.1.3 misho 1683: memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
1.1 misho 1684:
1685: bytelen = (family == AF_INET ? 4 : 16);
1686:
1687: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1.1.1.4 ! misho 1688: req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST;
1.1 misho 1689: req.n.nlmsg_type = cmd;
1690: req.r.rtm_family = family;
1691: req.r.rtm_table = rib->table;
1692: req.r.rtm_dst_len = p->prefixlen;
1693: req.r.rtm_protocol = RTPROT_ZEBRA;
1.1.1.4 ! misho 1694: req.r.rtm_scope = RT_SCOPE_LINK;
1.1 misho 1695:
1696: if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
1697: discard = 1;
1698: else
1699: discard = 0;
1700:
1701: if (cmd == RTM_NEWROUTE)
1702: {
1703: if (discard)
1704: {
1705: if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1706: req.r.rtm_type = RTN_BLACKHOLE;
1707: else if (rib->flags & ZEBRA_FLAG_REJECT)
1708: req.r.rtm_type = RTN_UNREACHABLE;
1709: else
1710: assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1711: }
1712: else
1713: req.r.rtm_type = RTN_UNICAST;
1714: }
1715:
1716: addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1717:
1718: /* Metric. */
1.1.1.4 ! misho 1719: addattr32 (&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
! 1720:
! 1721: if (rib->mtu || rib->nexthop_mtu)
! 1722: {
! 1723: char buf[NL_PKT_BUF_SIZE];
! 1724: struct rtattr *rta = (void *) buf;
! 1725: u_int32_t mtu = rib->mtu;
! 1726: if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu))
! 1727: mtu = rib->nexthop_mtu;
! 1728: rta->rta_type = RTA_METRICS;
! 1729: rta->rta_len = RTA_LENGTH(0);
! 1730: rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu);
! 1731: addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta),
! 1732: RTA_PAYLOAD (rta));
! 1733: }
1.1 misho 1734:
1735: if (discard)
1736: {
1737: if (cmd == RTM_NEWROUTE)
1.1.1.4 ! misho 1738: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
! 1739: {
! 1740: /* We shouldn't encounter recursive nexthops on discard routes,
! 1741: * but it is probably better to handle that case correctly anyway.
! 1742: */
! 1743: if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 1744: continue;
! 1745: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 1746: }
1.1 misho 1747: goto skip;
1748: }
1749:
1.1.1.4 ! misho 1750: /* Count overall nexthops so we can decide whether to use singlepath
! 1751: * or multipath case. */
! 1752: nexthop_num = 0;
! 1753: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
! 1754: {
! 1755: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 1756: continue;
! 1757: if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 1758: continue;
! 1759: if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
! 1760: continue;
! 1761:
! 1762: if (nexthop->type != NEXTHOP_TYPE_IFINDEX &&
! 1763: nexthop->type != NEXTHOP_TYPE_IFNAME)
! 1764: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
! 1765:
! 1766: nexthop_num++;
! 1767: }
! 1768:
! 1769: /* Singlepath case. */
! 1770: if (nexthop_num == 1 || MULTIPATH_NUM == 1)
1.1 misho 1771: {
1.1.1.4 ! misho 1772: nexthop_num = 0;
! 1773: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1.1 misho 1774: {
1.1.1.4 ! misho 1775: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 1776: continue;
1.1 misho 1777:
1778: if ((cmd == RTM_NEWROUTE
1779: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1780: || (cmd == RTM_DELROUTE
1781: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1782: {
1.1.1.4 ! misho 1783: routedesc = recursing ? "recursive, 1 hop" : "single hop";
1.1 misho 1784:
1.1.1.4 ! misho 1785: _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
! 1786: _netlink_route_build_singlepath(routedesc, bytelen,
! 1787: nexthop, &req.n, &req.r,
! 1788: sizeof req);
1.1 misho 1789:
1790: if (cmd == RTM_NEWROUTE)
1791: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1792:
1793: nexthop_num++;
1794: break;
1795: }
1796: }
1797: }
1798: else
1799: {
1.1.1.2 misho 1800: char buf[NL_PKT_BUF_SIZE];
1.1 misho 1801: struct rtattr *rta = (void *) buf;
1802: struct rtnexthop *rtnh;
1803: union g_addr *src = NULL;
1804:
1805: rta->rta_type = RTA_MULTIPATH;
1806: rta->rta_len = RTA_LENGTH (0);
1807: rtnh = RTA_DATA (rta);
1808:
1809: nexthop_num = 0;
1.1.1.4 ! misho 1810: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1.1 misho 1811: {
1.1.1.4 ! misho 1812: if (nexthop_num >= MULTIPATH_NUM)
! 1813: break;
! 1814:
! 1815: if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 1816: continue;
! 1817:
1.1 misho 1818: if ((cmd == RTM_NEWROUTE
1819: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1820: || (cmd == RTM_DELROUTE
1821: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1822: {
1.1.1.4 ! misho 1823: routedesc = recursing ? "recursive, multihop" : "multihop";
1.1 misho 1824: nexthop_num++;
1825:
1.1.1.4 ! misho 1826: _netlink_route_debug(cmd, p, nexthop,
! 1827: routedesc, family, zvrf);
! 1828: _netlink_route_build_multipath(routedesc, bytelen,
! 1829: nexthop, rta, rtnh, &src);
1.1 misho 1830: rtnh = RTNH_NEXT (rtnh);
1831:
1832: if (cmd == RTM_NEWROUTE)
1833: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1834: }
1835: }
1836: if (src)
1837: addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
1838:
1839: if (rta->rta_len > RTA_LENGTH (0))
1.1.1.2 misho 1840: addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
1.1 misho 1841: RTA_PAYLOAD (rta));
1842: }
1843:
1844: /* If there is no useful nexthop then return. */
1845: if (nexthop_num == 0)
1846: {
1847: if (IS_ZEBRA_DEBUG_KERNEL)
1848: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
1849: return 0;
1850: }
1851:
1852: skip:
1853:
1854: /* Destination netlink address. */
1855: memset (&snl, 0, sizeof snl);
1856: snl.nl_family = AF_NETLINK;
1857:
1858: /* Talk to netlink socket. */
1.1.1.4 ! misho 1859: return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
1.1 misho 1860: }
1861:
1862: int
1.1.1.4 ! misho 1863: kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
1.1 misho 1864: {
1.1.1.4 ! misho 1865: if (!old && new)
! 1866: return netlink_route_multipath (RTM_NEWROUTE, p, new);
! 1867: if (old && !new)
! 1868: return netlink_route_multipath (RTM_DELROUTE, p, old);
! 1869:
! 1870: /* Replace, can be done atomically if metric does not change;
! 1871: * netlink uses [prefix, tos, priority] to identify prefix.
! 1872: * Now metric is not sent to kernel, so we can just do atomic replace. */
! 1873: return netlink_route_multipath (RTM_NEWROUTE, p, new);
1.1 misho 1874: }
1875:
1876: /* Interface address modification. */
1877: static int
1878: netlink_address (int cmd, int family, struct interface *ifp,
1879: struct connected *ifc)
1880: {
1881: int bytelen;
1882: struct prefix *p;
1883:
1884: struct
1885: {
1886: struct nlmsghdr n;
1887: struct ifaddrmsg ifa;
1.1.1.2 misho 1888: char buf[NL_PKT_BUF_SIZE];
1.1 misho 1889: } req;
1890:
1.1.1.4 ! misho 1891: struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
! 1892:
1.1 misho 1893: p = ifc->address;
1.1.1.3 misho 1894: memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
1.1 misho 1895:
1896: bytelen = (family == AF_INET ? 4 : 16);
1897:
1898: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
1899: req.n.nlmsg_flags = NLM_F_REQUEST;
1900: req.n.nlmsg_type = cmd;
1901: req.ifa.ifa_family = family;
1902:
1903: req.ifa.ifa_index = ifp->ifindex;
1904: req.ifa.ifa_prefixlen = p->prefixlen;
1905:
1906: addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1907:
1908: if (family == AF_INET && cmd == RTM_NEWADDR)
1909: {
1910: if (!CONNECTED_PEER(ifc) && ifc->destination)
1911: {
1912: p = ifc->destination;
1913: addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1914: bytelen);
1915: }
1916: }
1917:
1918: if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1919: SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
1920:
1921: if (ifc->label)
1922: addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
1923: strlen (ifc->label) + 1);
1924:
1.1.1.4 ! misho 1925: return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
1.1 misho 1926: }
1927:
1928: int
1929: kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1930: {
1931: return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1932: }
1933:
1934: int
1935: kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1936: {
1937: return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1938: }
1939:
1940:
1941: extern struct thread_master *master;
1942:
1943: /* Kernel route reflection. */
1944: static int
1945: kernel_read (struct thread *thread)
1946: {
1.1.1.4 ! misho 1947: struct zebra_vrf *zvrf = (struct zebra_vrf *)THREAD_ARG (thread);
! 1948: netlink_parse_info (netlink_information_fetch, &zvrf->netlink, zvrf);
! 1949: zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf,
! 1950: zvrf->netlink.sock);
1.1 misho 1951:
1952: return 0;
1953: }
1954:
1955: /* Filter out messages from self that occur on listener socket,
1956: caused by our actions on the command socket
1957: */
1958: static void netlink_install_filter (int sock, __u32 pid)
1959: {
1960: struct sock_filter filter[] = {
1961: /* 0: ldh [4] */
1962: BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1963: /* 1: jeq 0x18 jt 3 jf 6 */
1964: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1965: /* 2: jeq 0x19 jt 3 jf 6 */
1966: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1967: /* 3: ldw [12] */
1968: BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1969: /* 4: jeq XX jt 5 jf 6 */
1970: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1971: /* 5: ret 0 (skip) */
1972: BPF_STMT(BPF_RET|BPF_K, 0),
1973: /* 6: ret 0xffff (keep) */
1974: BPF_STMT(BPF_RET|BPF_K, 0xffff),
1975: };
1976:
1977: struct sock_fprog prog = {
1.1.1.3 misho 1978: .len = array_size(filter),
1.1 misho 1979: .filter = filter,
1980: };
1981:
1982: if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1983: zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1984: }
1985:
1986: /* Exported interface function. This function simply calls
1987: netlink_socket (). */
1988: void
1.1.1.4 ! misho 1989: kernel_init (struct zebra_vrf *zvrf)
1.1 misho 1990: {
1991: unsigned long groups;
1992:
1993: groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
1994: #ifdef HAVE_IPV6
1995: groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
1996: #endif /* HAVE_IPV6 */
1.1.1.4 ! misho 1997: netlink_socket (&zvrf->netlink, groups, zvrf->vrf_id);
! 1998: netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id);
1.1 misho 1999:
2000: /* Register kernel socket. */
1.1.1.4 ! misho 2001: if (zvrf->netlink.sock > 0)
1.1 misho 2002: {
2003: /* Only want non-blocking on the netlink event socket */
1.1.1.4 ! misho 2004: if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
! 2005: zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name,
! 2006: safe_strerror (errno));
1.1 misho 2007:
2008: /* Set receive buffer size if it's set from command line */
2009: if (nl_rcvbufsize)
1.1.1.4 ! misho 2010: netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize);
1.1 misho 2011:
1.1.1.4 ! misho 2012: netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid);
! 2013: zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf,
! 2014: zvrf->netlink.sock);
! 2015: }
! 2016: }
! 2017:
! 2018: void
! 2019: kernel_terminate (struct zebra_vrf *zvrf)
! 2020: {
! 2021: THREAD_READ_OFF (zvrf->t_netlink);
! 2022:
! 2023: if (zvrf->netlink.sock >= 0)
! 2024: {
! 2025: close (zvrf->netlink.sock);
! 2026: zvrf->netlink.sock = -1;
! 2027: }
! 2028:
! 2029: if (zvrf->netlink_cmd.sock >= 0)
! 2030: {
! 2031: close (zvrf->netlink_cmd.sock);
! 2032: zvrf->netlink_cmd.sock = -1;
1.1 misho 2033: }
2034: }
1.1.1.3 misho 2035:
2036: /*
2037: * nl_msg_type_to_str
2038: */
2039: const char *
2040: nl_msg_type_to_str (uint16_t msg_type)
2041: {
2042: return lookup (nlmsg_str, msg_type);
2043: }
2044:
2045: /*
2046: * nl_rtproto_to_str
2047: */
2048: const char *
2049: nl_rtproto_to_str (u_char rtproto)
2050: {
2051: return lookup (rtproto_str, rtproto);
2052: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>