Annotation of embedaddon/pimdd/trace.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1998 by the University of Southern California.
3: * All rights reserved.
4: *
5: * Permission to use, copy, modify, and distribute this software and
6: * its documentation in source and binary forms for lawful
7: * non-commercial purposes and without fee is hereby granted, provided
8: * that the above copyright notice appear in all copies and that both
9: * the copyright notice and this permission notice appear in supporting
10: * documentation, and that any documentation, advertising materials,
11: * and other materials related to such distribution and use acknowledge
12: * that the software was developed by the University of Southern
13: * California and/or Information Sciences Institute.
14: * The name of the University of Southern California may not
15: * be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23: * NON-INFRINGEMENT.
24: *
25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
29: *
30: * Other copyrights might apply to parts of this software and are so
31: * noted when applicable.
32: */
33: /*
34: * Questions concerning this software should be directed to
35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
36: *
37: * $Id: trace.c,v 1.3 1998/06/01 22:27:15 kurtw Exp $
38: */
39: /*
40: * Part of this program has been derived from mrouted.
41: * The mrouted program is covered by the license in the accompanying file
42: * named "LICENSE.mrouted".
43: *
44: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
45: * Leland Stanford Junior University.
46: *
47: */
48:
49:
50: #include "defs.h"
51: #include "trace.h"
52:
53:
54: /* TODO */
55: /*
56: * Traceroute function which returns traceroute replies to the requesting
57: * router. Also forwards the request to downstream routers.
58: */
59: void
60: accept_mtrace(src, dst, group, data, no, datalen)
61: u_int32 src;
62: u_int32 dst;
63: u_int32 group;
64: char *data;
65: u_int no; /* promoted u_char */
66: int datalen;
67: {
68: u_char type;
69: mrtentry_t *mrt;
70: struct tr_query *qry;
71: struct tr_resp *resp;
72: int vifi;
73: char *p;
74: int rcount;
75: int errcode = TR_NO_ERR;
76: int resptype;
77: struct timeval tp;
78: struct sioc_vif_req v_req;
79: u_int32 parent_address;
80:
81: /* Remember qid across invocations */
82: static u_int32 oqid = 0;
83:
84: /* timestamp the request/response */
85: gettimeofday(&tp, 0);
86:
87: /*
88: * Check if it is a query or a response
89: */
90: if (datalen == QLEN) {
91: type = QUERY;
92: IF_DEBUG(DEBUG_TRACE)
93: log(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
94: inet_fmt(src, s1), inet_fmt(dst, s2));
95: }
96: else if ((datalen - QLEN) % RLEN == 0) {
97: type = RESP;
98: IF_DEBUG(DEBUG_TRACE)
99: log(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
100: inet_fmt(src, s1), inet_fmt(dst, s2));
101: if (IN_MULTICAST(ntohl(dst))) {
102: IF_DEBUG(DEBUG_TRACE)
103: log(LOG_DEBUG, 0, "Dropping multicast response");
104: return;
105: }
106: }
107: else {
108: log(LOG_WARNING, 0, "%s from %s to %s",
109: "Non decipherable traceroute request recieved",
110: inet_fmt(src, s1), inet_fmt(dst, s2));
111: return;
112: }
113:
114: qry = (struct tr_query *)data;
115:
116: /*
117: * if it is a packet with all reports filled, drop it
118: */
119: if ((rcount = (datalen - QLEN)/RLEN) == no) {
120: IF_DEBUG(DEBUG_TRACE)
121: log(LOG_DEBUG, 0, "packet with all reports filled in");
122: return;
123: }
124:
125: IF_DEBUG(DEBUG_TRACE) {
126: log(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
127: inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
128: log(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
129: inet_fmt(qry->tr_raddr, s1));
130: log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
131: }
132:
133: /* determine the routing table entry for this traceroute */
134: mrt = find_route(qry->tr_src, group, MRTF_SG | MRTF_WC | MRTF_PMBR,
135: DONT_CREATE);
136: IF_DEBUG(DEBUG_TRACE)
137: if (mrt != (mrtentry_t *)NULL) {
138: if (mrt->upstream != (pim_nbr_entry_t *)NULL)
139: parent_address = mrt->upstream->address;
140: else
141: parent_address = INADDR_ANY;
142: log(LOG_DEBUG, 0, "mrt parent vif: %d rtr: %s metric: %d",
143: mrt->incoming, inet_fmt(parent_address, s1), mrt->metric);
144: /* TODO
145: log(LOG_DEBUG, 0, "mrt origin %s",
146: RT_FMT(rt, s1));
147: */
148: } else
149: log(LOG_DEBUG, 0, "...no route");
150:
151: /*
152: * Query type packet - check if rte exists
153: * Check if the query destination is a vif connected to me.
154: * and if so, whether I should start response back
155: */
156: if (type == QUERY) {
157: if (oqid == qry->tr_qid) {
158: /*
159: * If the multicast router is a member of the group being
160: * queried, and the query is multicasted, then the router can
161: * recieve multiple copies of the same query. If we have already
162: * replied to this traceroute, just ignore it this time.
163: *
164: * This is not a total solution, but since if this fails you
165: * only get N copies, N <= the number of interfaces on the router,
166: * it is not fatal.
167: */
168: IF_DEBUG(DEBUG_TRACE)
169: log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
170: return;
171: }
172:
173: if (mrt == (mrtentry_t *)NULL) {
174: IF_DEBUG(DEBUG_TRACE)
175: log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
176: inet_fmt(qry->tr_src, s1));
177: if (IN_MULTICAST(ntohl(dst)))
178: return;
179: }
180: vifi = find_vif_direct(qry->tr_dst);
181:
182: if (vifi == NO_VIF) {
183: /* The traceroute destination is not on one of my subnet vifs. */
184: IF_DEBUG(DEBUG_TRACE)
185: log(LOG_DEBUG, 0, "Destination %s not an interface",
186: inet_fmt(qry->tr_dst, s1));
187: if (IN_MULTICAST(ntohl(dst)))
188: return;
189: errcode = TR_WRONG_IF;
190: } else if (mrt != (mrtentry_t *)NULL && !VIFM_ISSET(vifi, mrt->oifs)) {
191: IF_DEBUG(DEBUG_TRACE)
192: log(LOG_DEBUG, 0,
193: "Destination %s not on forwarding tree for src %s",
194: inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
195: if (IN_MULTICAST(ntohl(dst)))
196: return;
197: errcode = TR_WRONG_IF;
198: }
199: }
200: else {
201: /*
202: * determine which interface the packet came in on
203: * RESP packets travel hop-by-hop so this either traversed
204: * a tunnel or came from a directly attached mrouter.
205: */
206: if ((vifi = find_vif_direct(src)) == NO_VIF) {
207: IF_DEBUG(DEBUG_TRACE)
208: log(LOG_DEBUG, 0, "Wrong interface for packet");
209: errcode = TR_WRONG_IF;
210: }
211: }
212:
213: /* Now that we've decided to send a response, save the qid */
214: oqid = qry->tr_qid;
215:
216: IF_DEBUG(DEBUG_TRACE)
217: log(LOG_DEBUG, 0, "Sending traceroute response");
218:
219: /* copy the packet to the sending buffer */
220: p = igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
221:
222: bcopy(data, p, datalen);
223:
224: p += datalen;
225:
226: /*
227: * If there is no room to insert our reply, coopt the previous hop
228: * error indication to relay this fact.
229: */
230: if (p + sizeof(struct tr_resp) > igmp_send_buf + RECV_BUF_SIZE) {
231: resp = (struct tr_resp *)p - 1;
232: resp->tr_rflags = TR_NO_SPACE;
233: mrt = NULL;
234: goto sendit;
235: }
236:
237: /*
238: * fill in initial response fields
239: */
240: resp = (struct tr_resp *)p;
241: bzero(resp, sizeof(struct tr_resp));
242: datalen += RLEN;
243:
244: resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) +
245: ((tp.tv_usec << 10) / 15625));
246:
247: resp->tr_rproto = PROTO_PIM;
248: resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr;
249: resp->tr_fttl = (vifi == NO_VIF) ? 0 : uvifs[vifi].uv_threshold;
250: resp->tr_rflags = errcode;
251:
252: /*
253: * obtain # of packets out on interface
254: */
255: v_req.vifi = vifi;
256: if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
257: resp->tr_vifout = htonl(v_req.ocount);
258: else
259: resp->tr_vifout = 0xffffffff;
260:
261: /*
262: * fill in scoping & pruning information
263: */
264: /* TODO */
265: #if 0
266: if (mrt != (mrtentry_t *)NULL)
267: for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
268: if (gt->gt_mcastgrp >= group)
269: break;
270: }
271: else
272: gt = NULL;
273:
274: if (gt && gt->gt_mcastgrp == group) {
275: struct stable *st;
276:
277: for (st = gt->gt_srctbl; st; st = st->st_next)
278: if (qry->tr_src == st->st_origin)
279: break;
280:
281: sg_req.src.s_addr = qry->tr_src;
282: sg_req.grp.s_addr = group;
283: if (st && st->st_ctime != 0 &&
284: ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
285: resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt);
286: else
287: resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff);
288:
289: if (VIFM_ISSET(vifi, gt->gt_scope))
290: resp->tr_rflags = TR_SCOPED;
291: else if (gt->gt_prsent_timer)
292: resp->tr_rflags = TR_PRUNED;
293: else if (!VIFM_ISSET(vifi, gt->gt_grpmems))
294: if (VIFM_ISSET(vifi, rt->rt_children) &&
295: NBRM_ISSETMASK(uvifs[vifi].uv_nbrmap, rt->rt_subordinates)) /*XXX*/
296: resp->tr_rflags = TR_OPRUNED;
297: else
298: resp->tr_rflags = TR_NO_FWD;
299: } else {
300: if (scoped_addr(vifi, group))
301: resp->tr_rflags = TR_SCOPED;
302: else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
303: resp->tr_rflags = TR_NO_FWD;
304: }
305: #endif /* 0 */
306:
307: /*
308: * if no rte exists, set NO_RTE error
309: */
310: if (mrt == (mrtentry_t *)NULL) {
311: src = dst; /* the dst address of resp. pkt */
312: resp->tr_inaddr = 0;
313: resp->tr_rflags = TR_NO_RTE;
314: resp->tr_rmtaddr = 0;
315: } else {
316: /* get # of packets in on interface */
317: v_req.vifi = mrt->incoming;
318: if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
319: resp->tr_vifin = htonl(v_req.icount);
320: else
321: resp->tr_vifin = 0xffffffff;
322:
323: /* TODO
324: MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
325: */
326: src = uvifs[mrt->incoming].uv_lcl_addr;
327: resp->tr_inaddr = src;
328: if (mrt->upstream != (pim_nbr_entry_t *)NULL)
329: parent_address = mrt->upstream->address;
330: else
331: parent_address = INADDR_ANY;
332:
333: resp->tr_rmtaddr = parent_address;
334: if (!VIFM_ISSET(vifi, mrt->oifs)) {
335: IF_DEBUG(DEBUG_TRACE)
336: log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
337: inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
338: resp->tr_rflags = TR_WRONG_IF;
339: }
340: #if 0
341: if (rt->rt_metric >= UNREACHABLE) {
342: resp->tr_rflags = TR_NO_RTE;
343: /* Hack to send reply directly */
344: rt = NULL;
345: }
346: #endif /* 0 */
347: }
348:
349: sendit:
350: /*
351: * if metric is 1 or no. of reports is 1, send response to requestor
352: * else send to upstream router. If the upstream router can't handle
353: * mtrace, set an error code and send to requestor anyway.
354: */
355: IF_DEBUG(DEBUG_TRACE)
356: log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
357:
358: if ((rcount + 1 == no) || (mrt == NULL) || (mrt->metric == 1)) {
359: resptype = IGMP_MTRACE_RESP;
360: dst = qry->tr_raddr;
361: } else
362: /* TODO */
363: {
364: #if 0
365: if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
366: dst = qry->tr_raddr;
367: resp->tr_rflags = TR_OLD_ROUTER;
368: resptype = IGMP_MTRACE_RESP;
369: } else {
370: #endif /* 0 */
371: if (mrt->upstream != (pim_nbr_entry_t *)NULL)
372: parent_address = mrt->upstream->address;
373: else
374: parent_address = INADDR_ANY;
375: dst = parent_address;
376: resptype = IGMP_MTRACE;
377: }
378:
379: if (IN_MULTICAST(ntohl(dst))) {
380: /*
381: * Send the reply on a known multicast capable vif.
382: * If we don't have one, we can't source any multicasts anyway.
383: */
384: if (phys_vif != -1) {
385: IF_DEBUG(DEBUG_TRACE)
386: log(LOG_DEBUG, 0, "Sending reply to %s from %s",
387: inet_fmt(dst, s1),
388: inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2));
389: k_set_ttl(igmp_socket, qry->tr_rttl);
390: send_igmp(igmp_send_buf, uvifs[phys_vif].uv_lcl_addr, dst,
391: resptype, no, group, datalen);
392: k_set_ttl(igmp_socket, 1);
393: } else
394: log(LOG_INFO, 0, "No enabled phyints -- %s",
395: "dropping traceroute reply");
396: } else {
397: IF_DEBUG(DEBUG_TRACE)
398: log(LOG_DEBUG, 0, "Sending %s to %s from %s",
399: resptype == IGMP_MTRACE_RESP ? "reply" : "request on",
400: inet_fmt(dst, s1), inet_fmt(src, s2));
401:
402: send_igmp(igmp_send_buf, src, dst, resptype, no, group, datalen);
403: }
404: return;
405: }
406:
407:
408: /*
409: * accept_neighbor_request() supports some old DVMRP messages from mrinfo.
410: * Haven't tested it, because I have only the new mrinfo.
411: */
412: void
413: accept_neighbor_request(src, dst)
414: u_int32 src;
415: u_int32 dst;
416: {
417: vifi_t vifi;
418: struct uvif *v;
419: u_char *p, *ncount;
420: /* struct listaddr *la; */
421: pim_nbr_entry_t *pim_nbr;
422: int datalen;
423: u_int32 temp_addr, them = src;
424:
425: #define PUT_ADDR(a) temp_addr = ntohl(a); \
426: *p++ = temp_addr >> 24; \
427: *p++ = (temp_addr >> 16) & 0xFF; \
428: *p++ = (temp_addr >> 8) & 0xFF; \
429: *p++ = temp_addr & 0xFF;
430:
431: p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
432: datalen = 0;
433:
434: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
435: if (v->uv_flags & VIFF_DISABLED)
436: continue;
437:
438: ncount = 0;
439:
440: /* TODO: XXX: if we are PMBR, then check the DVMRP interfaces too */
441: for (pim_nbr = v->uv_pim_neighbors; pim_nbr != (pim_nbr_entry_t *)NULL;
442: pim_nbr = pim_nbr->next) {
443: /* Make sure that there's room for this neighbor... */
444: if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
445: send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
446: DVMRP_NEIGHBORS, htonl(PIMD_LEVEL), datalen);
447: p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
448: datalen = 0;
449: ncount = 0;
450: }
451:
452: /* Put out the header for this neighbor list... */
453: if (ncount == 0) {
454: PUT_ADDR(v->uv_lcl_addr);
455: *p++ = v->uv_metric;
456: *p++ = v->uv_threshold;
457: ncount = p;
458: *p++ = 0;
459: datalen += 4 + 3;
460: }
461:
462: PUT_ADDR(pim_nbr->address);
463: datalen += 4;
464: (*ncount)++;
465: }
466: }
467:
468: if (datalen != 0)
469: send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
470: htonl(PIMD_LEVEL), datalen);
471: }
472:
473:
474: /*
475: * Send a list of all of our neighbors to the requestor, `src'.
476: * Used for mrinfo support.
477: * XXX: currently, we cannot specify the used multicast routing protocol;
478: * only a protocol version is returned.
479: */
480: void
481: accept_neighbor_request2(src, dst)
482: u_int32 src;
483: u_int32 dst;
484: {
485: vifi_t vifi;
486: struct uvif *v;
487: u_char *p, *ncount;
488: /* struct listaddr *la; */
489: pim_nbr_entry_t *pim_nbr;
490: int datalen;
491: u_int32 them = src;
492:
493: p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
494: datalen = 0;
495:
496: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
497: register u_int32 vflags = v->uv_flags;
498: register u_char rflags = 0;
499: if (vflags & VIFF_TUNNEL)
500: rflags |= DVMRP_NF_TUNNEL;
501: if (vflags & VIFF_SRCRT)
502: rflags |= DVMRP_NF_SRCRT;
503: if (vflags & VIFF_PIM_NBR)
504: rflags |= DVMRP_NF_PIM;
505: if (vflags & VIFF_DOWN)
506: rflags |= DVMRP_NF_DOWN;
507: if (vflags & VIFF_DISABLED)
508: rflags |= DVMRP_NF_DISABLED;
509: if (vflags & VIFF_QUERIER)
510: rflags |= DVMRP_NF_QUERIER;
511: if (vflags & VIFF_LEAF)
512: rflags |= DVMRP_NF_LEAF;
513: ncount = 0;
514: pim_nbr = v->uv_pim_neighbors;
515: if (pim_nbr == (pim_nbr_entry_t *)NULL) {
516: /*
517: * include down & disabled interfaces and interfaces on
518: * leaf nets.
519: */
520: if (rflags & DVMRP_NF_TUNNEL)
521: rflags |= DVMRP_NF_DOWN;
522: if (datalen > MAX_DVMRP_DATA_LEN - 12) {
523: send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
524: DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen);
525: p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
526: datalen = 0;
527: }
528: *(u_int*)p = v->uv_lcl_addr;
529: p += 4;
530: *p++ = v->uv_metric;
531: *p++ = v->uv_threshold;
532: *p++ = rflags;
533: *p++ = 1;
534: *(u_int*)p = v->uv_rmt_addr;
535: p += 4;
536: datalen += 12;
537: } else {
538: for ( ; pim_nbr; pim_nbr = pim_nbr->next) {
539: /* Make sure that there's room for this neighbor... */
540: if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
541: send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
542: DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen);
543: p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
544: datalen = 0;
545: ncount = 0;
546: }
547: /* Put out the header for this neighbor list... */
548: if (ncount == 0) {
549: *(u_int*)p = v->uv_lcl_addr;
550: p += 4;
551: *p++ = v->uv_metric;
552: *p++ = v->uv_threshold;
553: *p++ = rflags;
554: ncount = p;
555: *p++ = 0;
556: datalen += 4 + 4;
557: }
558: *(u_int*)p = pim_nbr->address;
559: p += 4;
560: datalen += 4;
561: (*ncount)++;
562: }
563: }
564: }
565: if (datalen != 0)
566: send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
567: DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen);
568: }
569:
570:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>