Annotation of embedaddon/quagga/pimd/pim_join.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   PIM for Quagga
        !             3:   Copyright (C) 2008  Everton da Silva Marques
        !             4: 
        !             5:   This program is free software; you can redistribute it and/or modify
        !             6:   it under the terms of the GNU General Public License as published by
        !             7:   the Free Software Foundation; either version 2 of the License, or
        !             8:   (at your option) any later version.
        !             9: 
        !            10:   This program is distributed in the hope that it will be useful, but
        !            11:   WITHOUT ANY WARRANTY; without even the implied warranty of
        !            12:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            13:   General Public License for more details.
        !            14:   
        !            15:   You should have received a copy of the GNU General Public License
        !            16:   along with this program; see the file COPYING; if not, write to the
        !            17:   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
        !            18:   MA 02110-1301 USA
        !            19:   
        !            20:   $QuaggaId: $Format:%an, %ai, %h$ $
        !            21: */
        !            22: 
        !            23: #include <zebra.h>
        !            24: 
        !            25: #include "log.h"
        !            26: #include "prefix.h"
        !            27: 
        !            28: #include "pimd.h"
        !            29: #include "pim_str.h"
        !            30: #include "pim_tlv.h"
        !            31: #include "pim_msg.h"
        !            32: #include "pim_pim.h"
        !            33: #include "pim_join.h"
        !            34: #include "pim_iface.h"
        !            35: #include "pim_hello.h"
        !            36: #include "pim_ifchannel.h"
        !            37: 
        !            38: static void on_trace(const char *label,
        !            39:                     struct interface *ifp, struct in_addr src)
        !            40: {
        !            41:   if (PIM_DEBUG_PIM_TRACE) {
        !            42:     char src_str[100];
        !            43:     pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
        !            44:     zlog_debug("%s: from %s on %s",
        !            45:               label, src_str, ifp->name);
        !            46:   }
        !            47: }
        !            48: 
        !            49: static void recv_join(struct interface *ifp,
        !            50:                      struct pim_neighbor *neigh,
        !            51:                      uint16_t holdtime,
        !            52:                      struct in_addr upstream,
        !            53:                      struct in_addr group,
        !            54:                      struct in_addr source,
        !            55:                      uint8_t source_flags)
        !            56: {
        !            57:   if (PIM_DEBUG_PIM_TRACE) {
        !            58:     char up_str[100];
        !            59:     char src_str[100];
        !            60:     char grp_str[100];
        !            61:     char neigh_str[100];
        !            62:     pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
        !            63:     pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
        !            64:     pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
        !            65:     pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
        !            66:     zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
        !            67:              __PRETTY_FUNCTION__,
        !            68:              src_str, grp_str,
        !            69:              source_flags & PIM_RPT_BIT_MASK,
        !            70:              source_flags & PIM_WILDCARD_BIT_MASK,
        !            71:              up_str, holdtime, neigh_str, ifp->name);
        !            72:   }
        !            73:   
        !            74:   /* Restart join expiry timer */
        !            75:   pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
        !            76:                         source, group, source_flags, holdtime);
        !            77: }
        !            78: 
        !            79: static void recv_prune(struct interface *ifp,
        !            80:                       struct pim_neighbor *neigh,
        !            81:                       uint16_t holdtime,
        !            82:                       struct in_addr upstream,
        !            83:                       struct in_addr group,
        !            84:                       struct in_addr source,
        !            85:                       uint8_t source_flags)
        !            86: {
        !            87:   if (PIM_DEBUG_PIM_TRACE) {
        !            88:     char up_str[100];
        !            89:     char src_str[100];
        !            90:     char grp_str[100];
        !            91:     char neigh_str[100];
        !            92:     pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
        !            93:     pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
        !            94:     pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
        !            95:     pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
        !            96:     zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
        !            97:              __PRETTY_FUNCTION__,
        !            98:              src_str, grp_str,
        !            99:              source_flags & PIM_RPT_BIT_MASK,
        !           100:              source_flags & PIM_WILDCARD_BIT_MASK,
        !           101:              up_str, holdtime, neigh_str, ifp->name);
        !           102:   }
        !           103:   
        !           104:   pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime);
        !           105: }
        !           106: 
        !           107: int pim_joinprune_recv(struct interface *ifp,
        !           108:                       struct pim_neighbor *neigh,
        !           109:                       struct in_addr src_addr,
        !           110:                       uint8_t *tlv_buf, int tlv_buf_size)
        !           111: {
        !           112:   struct prefix   msg_upstream_addr;
        !           113:   uint8_t         msg_num_groups;
        !           114:   uint16_t        msg_holdtime;
        !           115:   int             addr_offset;
        !           116:   uint8_t        *buf;
        !           117:   uint8_t        *pastend;
        !           118:   int             remain;
        !           119:   int             group;
        !           120: 
        !           121:   on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
        !           122: 
        !           123:   buf     = tlv_buf;
        !           124:   pastend = tlv_buf + tlv_buf_size;
        !           125: 
        !           126:   /*
        !           127:     Parse ucast addr
        !           128:   */
        !           129:   addr_offset = pim_parse_addr_ucast(ifp->name, src_addr,
        !           130:                                     &msg_upstream_addr,
        !           131:                                     buf, pastend - buf);
        !           132: #if 0
        !           133:   zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d",
        !           134:             __PRETTY_FUNCTION__,
        !           135:             addr_offset);
        !           136: #endif
        !           137:   if (addr_offset < 1) {
        !           138:     char src_str[100];
        !           139:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           140:     zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
        !           141:              __PRETTY_FUNCTION__,
        !           142:              src_str, ifp->name);
        !           143:     return -1;
        !           144:   }
        !           145:   buf += addr_offset;
        !           146: 
        !           147:   /*
        !           148:     Check upstream address family
        !           149:    */
        !           150:   if (msg_upstream_addr.family != AF_INET) {
        !           151:     if (PIM_DEBUG_PIM_TRACE) {
        !           152:       char src_str[100];
        !           153:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           154:       zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
        !           155:                __PRETTY_FUNCTION__,
        !           156:                msg_upstream_addr.family, src_str, ifp->name);
        !           157:     }
        !           158:     return -2;
        !           159:   }
        !           160: 
        !           161:   remain = pastend - buf;
        !           162:   if (remain < 4) {
        !           163:     char src_str[100];
        !           164:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           165:     zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
        !           166:              __PRETTY_FUNCTION__,
        !           167:              remain, 4, src_str, ifp->name);
        !           168:     return -4;
        !           169:   }
        !           170: 
        !           171:   ++buf; /* skip reserved byte */
        !           172:   msg_num_groups = *(const uint8_t *) buf;
        !           173:   ++buf;
        !           174:   msg_holdtime = ntohs(*(const uint16_t *) buf);
        !           175:   ++buf;
        !           176:   ++buf;
        !           177: 
        !           178:   if (PIM_DEBUG_PIM_TRACE) {
        !           179:     char src_str[100];
        !           180:     char upstream_str[100];
        !           181:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           182:     pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
        !           183:                   upstream_str, sizeof(upstream_str));
        !           184:     zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
        !           185:              __PRETTY_FUNCTION__,
        !           186:              upstream_str, msg_num_groups, msg_holdtime,
        !           187:              src_str, ifp->name);
        !           188:   }
        !           189: 
        !           190:   /* Scan groups */
        !           191:   for (group = 0; group < msg_num_groups; ++group) {
        !           192:     struct prefix msg_group_addr;
        !           193:     struct prefix msg_source_addr;
        !           194:     uint8_t       msg_source_flags;
        !           195:     uint16_t      msg_num_joined_sources;
        !           196:     uint16_t      msg_num_pruned_sources;
        !           197:     int           source;
        !           198: 
        !           199:     addr_offset = pim_parse_addr_group(ifp->name, src_addr,
        !           200:                                       &msg_group_addr,
        !           201:                                       buf, pastend - buf);
        !           202: #if 0
        !           203:     zlog_warn("%s: pim_parse_addr_group addr_offset=%d",
        !           204:               __PRETTY_FUNCTION__,
        !           205:               addr_offset);
        !           206: #endif
        !           207:     if (addr_offset < 1) {
        !           208:       return -5;
        !           209:     }
        !           210:     buf += addr_offset;
        !           211: 
        !           212:     remain = pastend - buf;
        !           213:     if (remain < 4) {
        !           214:       char src_str[100];
        !           215:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           216:       zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
        !           217:                __PRETTY_FUNCTION__,
        !           218:                remain, 4, src_str, ifp->name);
        !           219:       return -6;
        !           220:     }
        !           221: 
        !           222:     msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
        !           223:     buf += 2;
        !           224:     msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
        !           225:     buf += 2;
        !           226: 
        !           227:     if (PIM_DEBUG_PIM_TRACE) {
        !           228:       char src_str[100];
        !           229:       char upstream_str[100];
        !           230:       char group_str[100];
        !           231:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
        !           232:       pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
        !           233:                     upstream_str, sizeof(upstream_str));
        !           234:       pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
        !           235:                     group_str, sizeof(group_str));
        !           236:       zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
        !           237:                __PRETTY_FUNCTION__,
        !           238:                upstream_str, group_str, msg_group_addr.prefixlen,
        !           239:                msg_num_joined_sources, msg_num_pruned_sources,
        !           240:                src_str, ifp->name);
        !           241:     }
        !           242: 
        !           243:     /* Scan joined sources */
        !           244:     for (source = 0; source < msg_num_joined_sources; ++source) {
        !           245:       addr_offset = pim_parse_addr_source(ifp->name, src_addr,
        !           246:                                          &msg_source_addr,
        !           247:                                          &msg_source_flags,
        !           248:                                          buf, pastend - buf);
        !           249: #if 0
        !           250:       zlog_warn("%s: pim_parse_addr_source addr_offset=%d",
        !           251:                 __PRETTY_FUNCTION__,
        !           252:                 addr_offset);
        !           253: #endif
        !           254:       if (addr_offset < 1) {
        !           255:        return -7;
        !           256:       }
        !           257: 
        !           258:       buf += addr_offset;
        !           259: 
        !           260:       recv_join(ifp, neigh, msg_holdtime,
        !           261:                msg_upstream_addr.u.prefix4,
        !           262:                msg_group_addr.u.prefix4,
        !           263:                msg_source_addr.u.prefix4,
        !           264:                msg_source_flags);
        !           265:     }
        !           266: 
        !           267:     /* Scan pruned sources */
        !           268:     for (source = 0; source < msg_num_pruned_sources; ++source) {
        !           269:       addr_offset = pim_parse_addr_source(ifp->name, src_addr,
        !           270:                                          &msg_source_addr,
        !           271:                                          &msg_source_flags,
        !           272:                                          buf, pastend - buf);
        !           273:       if (addr_offset < 1) {
        !           274:        return -8;
        !           275:       }
        !           276: 
        !           277:       buf += addr_offset;
        !           278: 
        !           279:       recv_prune(ifp, neigh, msg_holdtime,
        !           280:                 msg_upstream_addr.u.prefix4,
        !           281:                 msg_group_addr.u.prefix4,
        !           282:                 msg_source_addr.u.prefix4,
        !           283:                 msg_source_flags);
        !           284:     }
        !           285: 
        !           286:   } /* scan groups */
        !           287: 
        !           288:   return 0;
        !           289: }
        !           290: 
        !           291: int pim_joinprune_send(struct interface *ifp,
        !           292:                       struct in_addr upstream_addr,
        !           293:                       struct in_addr source_addr,
        !           294:                       struct in_addr group_addr,
        !           295:                       int send_join)
        !           296: {
        !           297:   struct pim_interface *pim_ifp;
        !           298:   uint8_t pim_msg[1000];
        !           299:   const uint8_t *pastend = pim_msg + sizeof(pim_msg);
        !           300:   uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
        !           301:   int pim_msg_size;
        !           302:   int remain;
        !           303: 
        !           304:   zassert(ifp);
        !           305: 
        !           306:   pim_ifp = ifp->info;
        !           307: 
        !           308:   if (!pim_ifp) {
        !           309:     zlog_warn("%s: multicast not enabled on interface %s",
        !           310:              __PRETTY_FUNCTION__,
        !           311:              ifp->name);
        !           312:     return -1;
        !           313:   }
        !           314: 
        !           315:   if (PIM_DEBUG_PIM_TRACE) {
        !           316:     char source_str[100];
        !           317:     char group_str[100];
        !           318:     char dst_str[100];
        !           319:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
        !           320:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
        !           321:     pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
        !           322:     zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
        !           323:               __PRETTY_FUNCTION__,
        !           324:               send_join ? "Join" : "Prune",
        !           325:               source_str, group_str, dst_str, ifp->name);
        !           326:   }
        !           327: 
        !           328:   if (PIM_INADDR_IS_ANY(upstream_addr)) {
        !           329:     if (PIM_DEBUG_PIM_TRACE) {
        !           330:       char source_str[100];
        !           331:       char group_str[100];
        !           332:       char dst_str[100];
        !           333:       pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
        !           334:       pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
        !           335:       pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
        !           336:       zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
        !           337:                 __PRETTY_FUNCTION__,
        !           338:                 send_join ? "Join" : "Prune",
        !           339:                 source_str, group_str, dst_str, ifp->name);
        !           340:     }
        !           341:     return 0;
        !           342:   }
        !           343: 
        !           344:   /*
        !           345:     RFC 4601: 4.3.1.  Sending Hello Messages
        !           346: 
        !           347:     Thus, if a router needs to send a Join/Prune or Assert message on
        !           348:     an interface on which it has not yet sent a Hello message with the
        !           349:     currently configured IP address, then it MUST immediately send the
        !           350:     relevant Hello message without waiting for the Hello Timer to
        !           351:     expire, followed by the Join/Prune or Assert message.
        !           352:   */
        !           353:   pim_hello_require(ifp);
        !           354: 
        !           355:   /*
        !           356:     Build PIM message
        !           357:   */
        !           358: 
        !           359:   remain = pastend - pim_msg_curr;
        !           360:   pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
        !           361:                                                remain,
        !           362:                                                upstream_addr);
        !           363:   if (!pim_msg_curr) {
        !           364:     char dst_str[100];
        !           365:     pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
        !           366:     zlog_warn("%s: failure encoding destination address %s: space left=%d",
        !           367:              __PRETTY_FUNCTION__, dst_str, remain);
        !           368:     return -3;
        !           369:   }
        !           370: 
        !           371:   remain = pastend - pim_msg_curr;
        !           372:   if (remain < 4) {
        !           373:     zlog_warn("%s: group will not fit: space left=%d",
        !           374:            __PRETTY_FUNCTION__, remain);
        !           375:     return -4;
        !           376:   }
        !           377: 
        !           378:   *pim_msg_curr = 0; /* reserved */
        !           379:   ++pim_msg_curr;
        !           380:   *pim_msg_curr = 1; /* number of groups */
        !           381:   ++pim_msg_curr;
        !           382:   *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
        !           383:   ++pim_msg_curr;
        !           384:   ++pim_msg_curr;
        !           385: 
        !           386:   remain = pastend - pim_msg_curr;
        !           387:   pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
        !           388:                                                remain,
        !           389:                                                group_addr);
        !           390:   if (!pim_msg_curr) {
        !           391:     char group_str[100];
        !           392:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
        !           393:     zlog_warn("%s: failure encoding group address %s: space left=%d",
        !           394:              __PRETTY_FUNCTION__, group_str, remain);
        !           395:     return -5;
        !           396:   }
        !           397: 
        !           398:   remain = pastend - pim_msg_curr;
        !           399:   if (remain < 4) {
        !           400:     zlog_warn("%s: sources will not fit: space left=%d",
        !           401:              __PRETTY_FUNCTION__, remain);
        !           402:     return -6;
        !           403:   }
        !           404: 
        !           405:   /* number of joined sources */
        !           406:   *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
        !           407:   ++pim_msg_curr;
        !           408:   ++pim_msg_curr;
        !           409: 
        !           410:   /* number of pruned sources */
        !           411:   *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
        !           412:   ++pim_msg_curr;
        !           413:   ++pim_msg_curr;
        !           414: 
        !           415:   remain = pastend - pim_msg_curr;
        !           416:   pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
        !           417:                                                 remain,
        !           418:                                                 source_addr);
        !           419:   if (!pim_msg_curr) {
        !           420:     char source_str[100];
        !           421:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
        !           422:     zlog_warn("%s: failure encoding source address %s: space left=%d",
        !           423:              __PRETTY_FUNCTION__, source_str, remain);
        !           424:     return -7;
        !           425:   }
        !           426: 
        !           427:   /* Add PIM header */
        !           428: 
        !           429:   pim_msg_size = pim_msg_curr - pim_msg;
        !           430: 
        !           431:   pim_msg_build_header(pim_msg, pim_msg_size,
        !           432:                       PIM_MSG_TYPE_JOIN_PRUNE);
        !           433: 
        !           434:   if (pim_msg_send(pim_ifp->pim_sock_fd,
        !           435:                   qpim_all_pim_routers_addr,
        !           436:                   pim_msg,
        !           437:                   pim_msg_size,
        !           438:                   ifp->name)) {
        !           439:     zlog_warn("%s: could not send PIM message on interface %s",
        !           440:              __PRETTY_FUNCTION__, ifp->name);
        !           441:     return -8;
        !           442:   }
        !           443: 
        !           444:   return 0;
        !           445: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>