Annotation of embedaddon/quagga/pimd/pim_join.c, revision 1.1.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>