Annotation of embedaddon/quagga/zebra/zebra_fpm_netlink.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Code for encoding/decoding FPM messages that are in netlink format.
3: *
4: * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
5: * Copyright (C) 2012 by Open Source Routing.
6: * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
7: *
8: * This file is part of GNU Zebra.
9: *
10: * GNU Zebra is free software; you can redistribute it and/or modify it
11: * under the terms of the GNU General Public License as published by the
12: * Free Software Foundation; either version 2, or (at your option) any
13: * later version.
14: *
15: * GNU Zebra is distributed in the hope that it will be useful, but
16: * WITHOUT ANY WARRANTY; without even the implied warranty of
17: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18: * General Public License for more details.
19: *
20: * You should have received a copy of the GNU General Public License
21: * along with GNU Zebra; see the file COPYING. If not, write to the Free
22: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23: * 02111-1307, USA.
24: */
25:
26: #include <zebra.h>
27:
28: #include "log.h"
29: #include "rib.h"
30:
31: #include "rt_netlink.h"
32:
33: #include "zebra_fpm_private.h"
34:
35: /*
36: * addr_to_a
37: *
38: * Returns string representation of an address of the given AF.
39: */
40: static inline const char *
41: addr_to_a (u_char af, void *addr)
42: {
43: if (!addr)
44: return "<No address>";
45:
46: switch (af)
47: {
48:
49: case AF_INET:
50: return inet_ntoa (*((struct in_addr *) addr));
51:
52: #ifdef HAVE_IPV6
53: case AF_INET6:
54: return inet6_ntoa (*((struct in6_addr *) addr));
55: #endif
56:
57: default:
58: return "<Addr in unknown AF>";
59: }
60: }
61:
62: /*
63: * prefix_addr_to_a
64: *
65: * Convience wrapper that returns a human-readable string for the
66: * address in a prefix.
67: */
68: static const char *
69: prefix_addr_to_a (struct prefix *prefix)
70: {
71: if (!prefix)
72: return "<No address>";
73:
74: return addr_to_a (prefix->family, &prefix->u.prefix);
75: }
76:
77: /*
78: * af_addr_size
79: *
80: * The size of an address in a given address family.
81: */
82: static size_t
83: af_addr_size (u_char af)
84: {
85: switch (af)
86: {
87:
88: case AF_INET:
89: return 4;
90:
91: #ifdef HAVE_IPV6
92: case AF_INET6:
93: return 16;
94: #endif
95:
96: default:
97: assert(0);
98: return 16;
99: }
100: }
101:
102: /*
103: * netlink_nh_info_t
104: *
105: * Holds information about a single nexthop for netlink. These info
106: * structures are transient and may contain pointers into rib
107: * data structures for convenience.
108: */
109: typedef struct netlink_nh_info_t_
110: {
111: uint32_t if_index;
112: union g_addr *gateway;
113:
114: /*
115: * Information from the struct nexthop from which this nh was
116: * derived. For debug purposes only.
117: */
118: int recursive;
119: enum nexthop_types_t type;
120: } netlink_nh_info_t;
121:
122: /*
123: * netlink_route_info_t
124: *
125: * A structure for holding information for a netlink route message.
126: */
127: typedef struct netlink_route_info_t_
128: {
129: uint16_t nlmsg_type;
130: u_char rtm_type;
131: uint32_t rtm_table;
132: u_char rtm_protocol;
133: u_char af;
134: struct prefix *prefix;
135: uint32_t *metric;
136: int num_nhs;
137:
138: /*
1.1.1.2 ! misho 139: * Nexthop structures
1.1 misho 140: */
1.1.1.2 ! misho 141: netlink_nh_info_t nhs[MULTIPATH_NUM];
1.1 misho 142: union g_addr *pref_src;
143: } netlink_route_info_t;
144:
145: /*
146: * netlink_route_info_add_nh
147: *
148: * Add information about the given nexthop to the given route info
149: * structure.
150: *
151: * Returns TRUE if a nexthop was added, FALSE otherwise.
152: */
153: static int
1.1.1.2 ! misho 154: netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop,
! 155: int recursive)
1.1 misho 156: {
157: netlink_nh_info_t nhi;
158: union g_addr *src;
159:
160: memset (&nhi, 0, sizeof (nhi));
161: src = NULL;
162:
163: if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs))
164: return 0;
165:
1.1.1.2 ! misho 166: nhi.recursive = recursive;
1.1 misho 167: nhi.type = nexthop->type;
168: nhi.if_index = nexthop->ifindex;
169:
170: if (nexthop->type == NEXTHOP_TYPE_IPV4
171: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
172: {
173: nhi.gateway = &nexthop->gate;
174: if (nexthop->src.ipv4.s_addr)
175: src = &nexthop->src;
176: }
177:
178: #ifdef HAVE_IPV6
179: if (nexthop->type == NEXTHOP_TYPE_IPV6
180: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
181: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
182: {
183: nhi.gateway = &nexthop->gate;
184: }
185: #endif /* HAVE_IPV6 */
186:
187: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
188: || nexthop->type == NEXTHOP_TYPE_IFNAME)
189: {
190: if (nexthop->src.ipv4.s_addr)
191: src = &nexthop->src;
192: }
193:
194: if (!nhi.gateway && nhi.if_index == 0)
195: return 0;
196:
197: /*
198: * We have a valid nhi. Copy the structure over to the route_info.
199: */
200: ri->nhs[ri->num_nhs] = nhi;
201: ri->num_nhs++;
202:
203: if (src && !ri->pref_src)
204: ri->pref_src = src;
205:
206: return 1;
207: }
208:
209: /*
210: * netlink_proto_from_route_type
211: */
212: static u_char
213: netlink_proto_from_route_type (int type)
214: {
215: switch (type)
216: {
217: case ZEBRA_ROUTE_KERNEL:
218: case ZEBRA_ROUTE_CONNECT:
219: return RTPROT_KERNEL;
220:
221: default:
222: return RTPROT_ZEBRA;
223: }
224: }
225:
226: /*
227: * netlink_route_info_fill
228: *
229: * Fill out the route information object from the given route.
230: *
231: * Returns TRUE on success and FALSE on failure.
232: */
233: static int
234: netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
235: rib_dest_t *dest, struct rib *rib)
236: {
1.1.1.2 ! misho 237: struct nexthop *nexthop, *tnexthop;
! 238: int recursing;
1.1 misho 239: int discard;
240:
241: memset (ri, 0, sizeof (*ri));
242:
243: ri->prefix = rib_dest_prefix (dest);
244: ri->af = rib_dest_af (dest);
245:
246: ri->nlmsg_type = cmd;
1.1.1.2 ! misho 247: ri->rtm_table = rib_dest_vrf (dest)->vrf_id;
1.1 misho 248: ri->rtm_protocol = RTPROT_UNSPEC;
249:
250: /*
251: * An RTM_DELROUTE need not be accompanied by any nexthops,
252: * particularly in our communication with the FPM.
253: */
254: if (cmd == RTM_DELROUTE && !rib)
255: goto skip;
256:
257: if (rib)
258: ri->rtm_protocol = netlink_proto_from_route_type (rib->type);
259:
260: if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
261: discard = 1;
262: else
263: discard = 0;
264:
265: if (cmd == RTM_NEWROUTE)
266: {
267: if (discard)
268: {
269: if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
270: ri->rtm_type = RTN_BLACKHOLE;
271: else if (rib->flags & ZEBRA_FLAG_REJECT)
272: ri->rtm_type = RTN_UNREACHABLE;
273: else
274: assert (0);
275: }
276: else
277: ri->rtm_type = RTN_UNICAST;
278: }
279:
280: ri->metric = &rib->metric;
281:
282: if (discard)
283: {
284: goto skip;
285: }
286:
1.1.1.2 ! misho 287: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1.1 misho 288: {
1.1.1.2 ! misho 289: if (ri->num_nhs >= MULTIPATH_NUM)
! 290: break;
1.1 misho 291:
1.1.1.2 ! misho 292: if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 293: continue;
! 294:
! 295: if ((cmd == RTM_NEWROUTE
! 296: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 297: || (cmd == RTM_DELROUTE
! 298: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1.1 misho 299: {
1.1.1.2 ! misho 300: netlink_route_info_add_nh (ri, nexthop, recursing);
1.1 misho 301: }
302: }
303:
304: /* If there is no useful nexthop then return. */
305: if (ri->num_nhs == 0)
306: {
307: zfpm_debug ("netlink_encode_route(): No useful nexthop.");
308: return 0;
309: }
310:
311: skip:
312: return 1;
313: }
314:
315: /*
316: * netlink_route_info_encode
317: *
318: * Returns the number of bytes written to the buffer. 0 or a negative
319: * value indicates an error.
320: */
321: static int
322: netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf,
323: size_t in_buf_len)
324: {
325: int bytelen;
326: int nexthop_num = 0;
327: size_t buf_offset;
328: netlink_nh_info_t *nhi;
329:
330: struct
331: {
332: struct nlmsghdr n;
333: struct rtmsg r;
334: char buf[1];
335: } *req;
336:
337: req = (void *) in_buf;
338:
339: buf_offset = ((char *) req->buf) - ((char *) req);
340:
341: if (in_buf_len < buf_offset) {
342: assert(0);
343: return 0;
344: }
345:
346: memset (req, 0, buf_offset);
347:
348: bytelen = af_addr_size (ri->af);
349:
350: req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
351: req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
352: req->n.nlmsg_type = ri->nlmsg_type;
353: req->r.rtm_family = ri->af;
354: req->r.rtm_table = ri->rtm_table;
355: req->r.rtm_dst_len = ri->prefix->prefixlen;
356: req->r.rtm_protocol = ri->rtm_protocol;
357: req->r.rtm_scope = RT_SCOPE_UNIVERSE;
358:
359: addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen);
360:
361: req->r.rtm_type = ri->rtm_type;
362:
363: /* Metric. */
364: if (ri->metric)
365: addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric);
366:
367: if (ri->num_nhs == 0)
368: goto done;
369:
370: if (ri->num_nhs == 1)
371: {
372: nhi = &ri->nhs[0];
373:
374: if (nhi->gateway)
375: {
376: addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway,
377: bytelen);
378: }
379:
380: if (nhi->if_index)
381: {
382: addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index);
383: }
384:
385: goto done;
386:
387: }
388:
389: /*
390: * Multipath case.
391: */
392: char buf[NL_PKT_BUF_SIZE];
393: struct rtattr *rta = (void *) buf;
394: struct rtnexthop *rtnh;
395:
396: rta->rta_type = RTA_MULTIPATH;
397: rta->rta_len = RTA_LENGTH (0);
398: rtnh = RTA_DATA (rta);
399:
400: for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++)
401: {
402: nhi = &ri->nhs[nexthop_num];
403:
404: rtnh->rtnh_len = sizeof (*rtnh);
405: rtnh->rtnh_flags = 0;
406: rtnh->rtnh_hops = 0;
407: rtnh->rtnh_ifindex = 0;
408: rta->rta_len += rtnh->rtnh_len;
409:
410: if (nhi->gateway)
411: {
412: rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen);
413: rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
414: }
415:
416: if (nhi->if_index)
417: {
418: rtnh->rtnh_ifindex = nhi->if_index;
419: }
420:
421: rtnh = RTNH_NEXT (rtnh);
422: }
423:
424: assert (rta->rta_len > RTA_LENGTH (0));
425: addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta),
426: RTA_PAYLOAD (rta));
427:
428: done:
429:
430: if (ri->pref_src)
431: {
432: addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen);
433: }
434:
435: assert (req->n.nlmsg_len < in_buf_len);
436: return req->n.nlmsg_len;
437: }
438:
439: /*
440: * zfpm_log_route_info
441: *
442: * Helper function to log the information in a route_info structure.
443: */
444: static void
445: zfpm_log_route_info (netlink_route_info_t *ri, const char *label)
446: {
447: netlink_nh_info_t *nhi;
448: int i;
449:
450: zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label,
451: nl_msg_type_to_str (ri->nlmsg_type),
452: prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen,
453: nl_rtproto_to_str (ri->rtm_protocol),
454: ri->metric ? *ri->metric : 0);
455:
456: for (i = 0; i < ri->num_nhs; i++)
457: {
458: nhi = &ri->nhs[i];
459: zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s",
460: nhi->if_index, addr_to_a (ri->af, nhi->gateway),
461: nhi->recursive ? "yes" : "no",
462: nexthop_type_to_str (nhi->type));
463: }
464: }
465:
466: /*
467: * zfpm_netlink_encode_route
468: *
469: * Create a netlink message corresponding to the given route in the
470: * given buffer space.
471: *
472: * Returns the number of bytes written to the buffer. 0 or a negative
473: * value indicates an error.
474: */
475: int
476: zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib,
477: char *in_buf, size_t in_buf_len)
478: {
479: netlink_route_info_t ri_space, *ri;
480:
481: ri = &ri_space;
482:
483: if (!netlink_route_info_fill (ri, cmd, dest, rib))
484: return 0;
485:
486: zfpm_log_route_info (ri, __FUNCTION__);
487:
488: return netlink_route_info_encode (ri, in_buf, in_buf_len);
489: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>