Annotation of embedaddon/quagga/pimd/pim_mroute.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: #include "log.h"
                     25: #include "privs.h"
                     26: 
                     27: #include "pimd.h"
                     28: #include "pim_mroute.h"
                     29: #include "pim_str.h"
                     30: #include "pim_time.h"
                     31: #include "pim_iface.h"
                     32: #include "pim_macro.h"
                     33: 
                     34: /* GLOBAL VARS */
                     35: extern struct zebra_privs_t pimd_privs;
                     36: 
                     37: static void mroute_read_on(void);
                     38: 
                     39: static int pim_mroute_set(int fd, int enable)
                     40: {
                     41:   int err;
                     42:   int opt = enable ? MRT_INIT : MRT_DONE;
                     43:   socklen_t opt_len = sizeof(opt);
                     44: 
                     45:   err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
                     46:   if (err) {
                     47:     int e = errno;
                     48:     zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
                     49:              __FILE__, __PRETTY_FUNCTION__,
                     50:              fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e));
                     51:     errno = e;
                     52:     return -1;
                     53:   }
                     54: 
                     55: #if 0
                     56:   zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok",
                     57:            __FILE__, __PRETTY_FUNCTION__,
                     58:            fd, opt);
                     59: #endif
                     60: 
                     61:   return 0;
                     62: }
                     63: 
                     64: int pim_mroute_msg(int fd, const char *buf, int buf_size)
                     65: {
                     66:   struct interface     *ifp;
                     67:   const struct ip      *ip_hdr;
                     68:   const struct igmpmsg *msg;
                     69:   const char *upcall;
                     70:   char src_str[100];
                     71:   char grp_str[100];
                     72: 
                     73:   ip_hdr = (const struct ip *) buf;
                     74: 
                     75:   /* kernel upcall must have protocol=0 */
                     76:   if (ip_hdr->ip_p) {
                     77:     /* this is not a kernel upcall */
                     78: #ifdef PIM_UNEXPECTED_KERNEL_UPCALL
                     79:     zlog_warn("%s: not a kernel upcall proto=%d msg_size=%d",
                     80:              __PRETTY_FUNCTION__, ip_hdr->ip_p, buf_size);
                     81: #endif
                     82:     return 0;
                     83:   }
                     84: 
                     85:   msg = (const struct igmpmsg *) buf;
                     86: 
                     87:   switch (msg->im_msgtype) {
                     88:   case IGMPMSG_NOCACHE:  upcall = "NOCACHE";  break;
                     89:   case IGMPMSG_WRONGVIF: upcall = "WRONGVIF"; break;
                     90:   case IGMPMSG_WHOLEPKT: upcall = "WHOLEPKT"; break;
                     91:   default: upcall = "<unknown_upcall?>";
                     92:   }
                     93:   ifp = pim_if_find_by_vif_index(msg->im_vif);
                     94:   pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
                     95:   pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
                     96:     
                     97:   if (msg->im_msgtype == IGMPMSG_WRONGVIF) {
                     98:     struct pim_ifchannel *ch;
                     99:     struct pim_interface *pim_ifp;
                    100: 
                    101:     /*
                    102:       Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
                    103:       
                    104:       RFC 4601 4.8.2.  PIM-SSM-Only Routers
                    105:       
                    106:       iif is the incoming interface of the packet.
                    107:       if (iif is in inherited_olist(S,G)) {
                    108:       send Assert(S,G) on iif
                    109:       }
                    110:     */
                    111: 
                    112:     if (PIM_DEBUG_PIM_TRACE) {
                    113:       zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
                    114:                 __PRETTY_FUNCTION__,
                    115:                 fd,
                    116:                 src_str,
                    117:                 grp_str,
                    118:                 ifp ? ifp->name : "<ifname?>",
                    119:                 msg->im_vif);
                    120:     }
                    121: 
                    122:     if (!ifp) {
                    123:       zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
                    124:                __PRETTY_FUNCTION__,
                    125:                src_str, grp_str, msg->im_vif);
                    126:       return -1;
                    127:     }
                    128: 
                    129:     pim_ifp = ifp->info;
                    130:     if (!pim_ifp) {
                    131:       zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s",
                    132:                __PRETTY_FUNCTION__,
                    133:                src_str, grp_str, ifp->name);
                    134:       return -2;
                    135:     }
                    136: 
                    137:     ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst);
                    138:     if (!ch) {
                    139:       zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s",
                    140:                __PRETTY_FUNCTION__,
                    141:                src_str, grp_str, ifp->name);
                    142:       return -3;
                    143:     }
                    144: 
                    145:     /*
                    146:       RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    147: 
                    148:       Transitions from NoInfo State
                    149: 
                    150:       An (S,G) data packet arrives on interface I, AND
                    151:       CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
                    152:       downstream interface that is in our (S,G) outgoing interface
                    153:       list.  We optimistically assume that we will be the assert
                    154:       winner for this (S,G), and so we transition to the "I am Assert
                    155:       Winner" state and perform Actions A1 (below), which will
                    156:       initiate the assert negotiation for (S,G).
                    157:     */
                    158: 
                    159:     if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
                    160:       zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s",
                    161:                __PRETTY_FUNCTION__,
                    162:                src_str, grp_str, ifp->name);
                    163:       return -4;
                    164:     }
                    165: 
                    166:     if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
                    167:       zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel",
                    168:                __PRETTY_FUNCTION__,
                    169:                src_str, grp_str, ifp->name);
                    170:       return -5;
                    171:     }
                    172: 
                    173:     if (assert_action_a1(ch)) {
                    174:       zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
                    175:                __PRETTY_FUNCTION__,
                    176:                src_str, grp_str, ifp->name);
                    177:       return -6;
                    178:     }
                    179: 
                    180:     return 0;
                    181:   } /* IGMPMSG_WRONGVIF */
                    182: 
                    183:   zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
                    184:            __PRETTY_FUNCTION__,
                    185:            upcall,
                    186:            msg->im_msgtype,
                    187:            ip_hdr->ip_p,
                    188:            fd,
                    189:            src_str,
                    190:            grp_str,
                    191:            ifp ? ifp->name : "<ifname?>",
                    192:            msg->im_vif);
                    193: 
                    194:   return 0;
                    195: }
                    196: 
                    197: static int mroute_read_msg(int fd)
                    198: {
                    199:   const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg));
                    200:   char buf[1000];
                    201:   int rd;
                    202: 
                    203:   if (((int) sizeof(buf)) < msg_min_size) {
                    204:     zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d",
                    205:             __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size);
                    206:     return -1;
                    207:   }
                    208: 
                    209:   rd = read(fd, buf, sizeof(buf));
                    210:   if (rd < 0) {
                    211:     zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
                    212:              __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
                    213:     return -2;
                    214:   }
                    215: 
                    216:   if (rd < msg_min_size) {
                    217:     zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d",
                    218:              __PRETTY_FUNCTION__, fd, rd, msg_min_size);
                    219:     return -3;
                    220:   }
                    221: 
                    222:   return pim_mroute_msg(fd, buf, rd);
                    223: }
                    224: 
                    225: static int mroute_read(struct thread *t)
                    226: {
                    227:   int fd;
                    228:   int result;
                    229: 
                    230:   zassert(t);
                    231:   zassert(!THREAD_ARG(t));
                    232: 
                    233:   fd = THREAD_FD(t);
                    234:   zassert(fd == qpim_mroute_socket_fd);
                    235: 
                    236:   result = mroute_read_msg(fd);
                    237: 
                    238:   /* Keep reading */
                    239:   qpim_mroute_socket_reader = 0;
                    240:   mroute_read_on();
                    241: 
                    242:   return result;
                    243: }
                    244: 
                    245: static void mroute_read_on()
                    246: {
                    247:   zassert(!qpim_mroute_socket_reader);
                    248:   zassert(PIM_MROUTE_IS_ENABLED);
                    249: 
                    250:   THREAD_READ_ON(master, qpim_mroute_socket_reader,
                    251:                 mroute_read, 0, qpim_mroute_socket_fd);
                    252: }
                    253: 
                    254: static void mroute_read_off()
                    255: {
                    256:   THREAD_OFF(qpim_mroute_socket_reader);
                    257: }
                    258: 
                    259: int pim_mroute_socket_enable()
                    260: {
                    261:   int fd;
                    262: 
                    263:   if (PIM_MROUTE_IS_ENABLED)
                    264:     return -1;
                    265: 
                    266:   if ( pimd_privs.change (ZPRIVS_RAISE) )
                    267:     zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
                    268:               safe_strerror (errno) );
                    269: 
                    270:   fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
                    271: 
                    272:   if ( pimd_privs.change (ZPRIVS_LOWER) )
                    273:     zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
                    274:              safe_strerror (errno) );
                    275: 
                    276:   if (fd < 0) {
                    277:     zlog_warn("Could not create mroute socket: errno=%d: %s",
                    278:              errno, safe_strerror(errno));
                    279:     return -2;
                    280:   }
                    281: 
                    282:   if (pim_mroute_set(fd, 1)) {
                    283:     zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
                    284:              fd, errno, safe_strerror(errno));
                    285:     close(fd);
                    286:     return -3;
                    287:   }
                    288: 
                    289:   qpim_mroute_socket_fd       = fd;
                    290:   qpim_mroute_socket_creation = pim_time_monotonic_sec();
                    291:   mroute_read_on();
                    292: 
                    293:   zassert(PIM_MROUTE_IS_ENABLED);
                    294: 
                    295:   return 0;
                    296: }
                    297: 
                    298: int pim_mroute_socket_disable()
                    299: {
                    300:   if (PIM_MROUTE_IS_DISABLED)
                    301:     return -1;
                    302: 
                    303:   if (pim_mroute_set(qpim_mroute_socket_fd, 0)) {
                    304:     zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
                    305:              qpim_mroute_socket_fd, errno, safe_strerror(errno));
                    306:     return -2;
                    307:   }
                    308: 
                    309:   if (close(qpim_mroute_socket_fd)) {
                    310:     zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
                    311:              qpim_mroute_socket_fd, errno, safe_strerror(errno));
                    312:     return -3;
                    313:   }
                    314: 
                    315:   mroute_read_off();
                    316:   qpim_mroute_socket_fd = -1;
                    317: 
                    318:   zassert(PIM_MROUTE_IS_DISABLED);
                    319: 
                    320:   return 0;
                    321: }
                    322: 
                    323: /*
                    324:   For each network interface (e.g., physical or a virtual tunnel) that
                    325:   would be used for multicast forwarding, a corresponding multicast
                    326:   interface must be added to the kernel.
                    327:  */
                    328: int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr)
                    329: {
                    330:   struct vifctl vc;
                    331:   int err;
                    332: 
                    333:   if (PIM_MROUTE_IS_DISABLED) {
                    334:     zlog_warn("%s: global multicast is disabled",
                    335:              __PRETTY_FUNCTION__);
                    336:     return -1;
                    337:   }
                    338: 
                    339:   memset(&vc, 0, sizeof(vc));
                    340:   vc.vifc_vifi = vif_index;
                    341:   vc.vifc_flags = 0;
                    342:   vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
                    343:   vc.vifc_rate_limit = 0;
                    344:   memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
                    345: 
                    346: #ifdef PIM_DVMRP_TUNNEL  
                    347:   if (vc.vifc_flags & VIFF_TUNNEL) {
                    348:     memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr));
                    349:   }
                    350: #endif
                    351: 
                    352:   err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); 
                    353:   if (err) {
                    354:     char ifaddr_str[100];
                    355:     int e = errno;
                    356: 
                    357:     pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str));
                    358: 
                    359:     zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s",
                    360:              __FILE__, __PRETTY_FUNCTION__,
                    361:              qpim_mroute_socket_fd, vif_index, ifaddr_str,
                    362:              e, safe_strerror(e));
                    363:     errno = e;
                    364:     return -2;
                    365:   }
                    366: 
                    367:   return 0;
                    368: }
                    369: 
                    370: int pim_mroute_del_vif(int vif_index)
                    371: {
                    372:   struct vifctl vc;
                    373:   int err;
                    374: 
                    375:   if (PIM_MROUTE_IS_DISABLED) {
                    376:     zlog_warn("%s: global multicast is disabled",
                    377:              __PRETTY_FUNCTION__);
                    378:     return -1;
                    379:   }
                    380: 
                    381:   memset(&vc, 0, sizeof(vc));
                    382:   vc.vifc_vifi = vif_index;
                    383: 
                    384:   err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc)); 
                    385:   if (err) {
                    386:     int e = errno;
                    387:     zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
                    388:              __FILE__, __PRETTY_FUNCTION__,
                    389:              qpim_mroute_socket_fd, vif_index,
                    390:              e, safe_strerror(e));
                    391:     errno = e;
                    392:     return -2;
                    393:   }
                    394: 
                    395:   return 0;
                    396: }
                    397: 
                    398: int pim_mroute_add(struct mfcctl *mc)
                    399: {
                    400:   int err;
                    401: 
                    402:   qpim_mroute_add_last = pim_time_monotonic_sec();
                    403:   ++qpim_mroute_add_events;
                    404: 
                    405:   if (PIM_MROUTE_IS_DISABLED) {
                    406:     zlog_warn("%s: global multicast is disabled",
                    407:              __PRETTY_FUNCTION__);
                    408:     return -1;
                    409:   }
                    410: 
                    411:   err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
                    412:                   mc, sizeof(*mc));
                    413:   if (err) {
                    414:     int e = errno;
                    415:     zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
                    416:              __FILE__, __PRETTY_FUNCTION__,
                    417:              qpim_mroute_socket_fd,
                    418:              e, safe_strerror(e));
                    419:     errno = e;
                    420:     return -2;
                    421:   }
                    422: 
                    423:   return 0;
                    424: }
                    425: 
                    426: int pim_mroute_del(struct mfcctl *mc)
                    427: {
                    428:   int err;
                    429: 
                    430:   qpim_mroute_del_last = pim_time_monotonic_sec();
                    431:   ++qpim_mroute_del_events;
                    432: 
                    433:   if (PIM_MROUTE_IS_DISABLED) {
                    434:     zlog_warn("%s: global multicast is disabled",
                    435:              __PRETTY_FUNCTION__);
                    436:     return -1;
                    437:   }
                    438: 
                    439:   err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc));
                    440:   if (err) {
                    441:     int e = errno;
                    442:     zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
                    443:              __FILE__, __PRETTY_FUNCTION__,
                    444:              qpim_mroute_socket_fd,
                    445:              e, safe_strerror(e));
                    446:     errno = e;
                    447:     return -2;
                    448:   }
                    449: 
                    450:   return 0;
                    451: }

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