File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_mroute.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>