From f1bad8260c8c9942057c569b2a1a687a92b54862 Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 11 Aug 2009 15:43:05 -0300 Subject: [pim] Initial pim 0.155 --- pimd/pim_mroute.c | 432 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 pimd/pim_mroute.c (limited to 'pimd/pim_mroute.c') diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c new file mode 100644 index 00000000..f021abaa --- /dev/null +++ b/pimd/pim_mroute.c @@ -0,0 +1,432 @@ +/* + PIM for Quagga + Copyright (C) 2008 Everton da Silva Marques + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA + + $QuaggaId: $Format:%an, %ai, %h$ $ +*/ + +#include +#include "log.h" + +#include "pimd.h" +#include "pim_mroute.h" +#include "pim_str.h" +#include "pim_time.h" +#include "pim_iface.h" +#include "pim_macro.h" + +static void mroute_read_on(void); + +static int pim_mroute_set(int fd, int enable) +{ + int err; + int opt = enable ? MRT_INIT : MRT_DONE; + socklen_t opt_len = sizeof(opt); + + err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, strerror(e)); + errno = e; + return -1; + } + +#if 0 + zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok", + __FILE__, __PRETTY_FUNCTION__, + fd, opt); +#endif + + return 0; +} + +int pim_mroute_msg(int fd, const char *buf, int buf_size) +{ + struct interface *ifp; + const struct ip *ip_hdr; + const struct igmpmsg *msg; + const char *upcall; + char src_str[100]; + char grp_str[100]; + + ip_hdr = (const struct ip *) buf; + + /* kernel upcall must have protocol=0 */ + if (ip_hdr->ip_p) { + /* this is not a kernel upcall */ +#ifdef PIM_UNEXPECTED_KERNEL_UPCALL + zlog_warn("%s: not a kernel upcall proto=%d msg_size=%d", + __PRETTY_FUNCTION__, ip_hdr->ip_p, buf_size); +#endif + return 0; + } + + msg = (const struct igmpmsg *) buf; + + switch (msg->im_msgtype) { + case IGMPMSG_NOCACHE: upcall = "NOCACHE"; break; + case IGMPMSG_WRONGVIF: upcall = "WRONGVIF"; break; + case IGMPMSG_WHOLEPKT: upcall = "WHOLEPKT"; break; + default: upcall = ""; + } + ifp = pim_if_find_by_vif_index(msg->im_vif); + pim_inet4_dump("", msg->im_src, src_str, sizeof(src_str)); + pim_inet4_dump("", msg->im_dst, grp_str, sizeof(grp_str)); + + if (msg->im_msgtype == IGMPMSG_WRONGVIF) { + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp; + + /* + Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. + + RFC 4601 4.8.2. PIM-SSM-Only Routers + + iif is the incoming interface of the packet. + if (iif is in inherited_olist(S,G)) { + send Assert(S,G) on iif + } + */ + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", + __PRETTY_FUNCTION__, + fd, + src_str, + grp_str, + ifp ? ifp->name : "", + msg->im_vif); + } + + if (!ifp) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, + src_str, grp_str, msg->im_vif); + return -1; + } + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -2; + } + + ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst); + if (!ch) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -3; + } + + /* + RFC 4601: 4.6.1. (S,G) Assert Message State Machine + + Transitions from NoInfo State + + An (S,G) data packet arrives on interface I, AND + CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an + downstream interface that is in our (S,G) outgoing interface + list. We optimistically assume that we will be the assert + winner for this (S,G), and so we transition to the "I am Assert + Winner" state and perform Actions A1 (below), which will + initiate the assert negotiation for (S,G). + */ + + if (ch->ifassert_state != PIM_IFASSERT_NOINFO) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -4; + } + + if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -5; + } + + if (assert_action_a1(ch)) { + zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s", + __PRETTY_FUNCTION__, + src_str, grp_str, ifp->name); + return -6; + } + + return 0; + } /* IGMPMSG_WRONGVIF */ + + zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", + __PRETTY_FUNCTION__, + upcall, + msg->im_msgtype, + ip_hdr->ip_p, + fd, + src_str, + grp_str, + ifp ? ifp->name : "", + msg->im_vif); + + return 0; +} + +static int mroute_read_msg(int fd) +{ + const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg)); + char buf[1000]; + int rd; + + if (((int) sizeof(buf)) < msg_min_size) { + zlog_err("%s: fd=%d: buf size=%d lower than msg_min=%d", + __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size); + return -1; + } + + rd = read(fd, buf, sizeof(buf)); + if (rd < 0) { + zlog_warn("%s: failure reading fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, strerror(errno)); + return -2; + } + + if (rd < msg_min_size) { + zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d", + __PRETTY_FUNCTION__, fd, rd, msg_min_size); + return -3; + } + + return pim_mroute_msg(fd, buf, rd); +} + +static int mroute_read(struct thread *t) +{ + int fd; + int result; + + zassert(t); + zassert(!THREAD_ARG(t)); + + fd = THREAD_FD(t); + zassert(fd == qpim_mroute_socket_fd); + + result = mroute_read_msg(fd); + + /* Keep reading */ + qpim_mroute_socket_reader = 0; + mroute_read_on(); + + return result; +} + +static void mroute_read_on() +{ + zassert(!qpim_mroute_socket_reader); + zassert(PIM_MROUTE_IS_ENABLED); + + THREAD_READ_ON(master, qpim_mroute_socket_reader, + mroute_read, 0, qpim_mroute_socket_fd); +} + +static void mroute_read_off() +{ + THREAD_OFF(qpim_mroute_socket_reader); +} + +int pim_mroute_socket_enable() +{ + int fd; + + if (PIM_MROUTE_IS_ENABLED) + return -1; + + fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + if (fd < 0) { + zlog_warn("Could not create mroute socket: errno=%d: %s", + errno, strerror(errno)); + return -2; + } + + if (pim_mroute_set(fd, 1)) { + zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s", + fd, errno, strerror(errno)); + close(fd); + return -3; + } + + qpim_mroute_socket_fd = fd; + qpim_mroute_socket_creation = pim_time_monotonic_sec(); + mroute_read_on(); + + zassert(PIM_MROUTE_IS_ENABLED); + + return 0; +} + +int pim_mroute_socket_disable() +{ + if (PIM_MROUTE_IS_DISABLED) + return -1; + + if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { + zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s", + qpim_mroute_socket_fd, errno, strerror(errno)); + return -2; + } + + if (close(qpim_mroute_socket_fd)) { + zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", + qpim_mroute_socket_fd, errno, strerror(errno)); + return -3; + } + + mroute_read_off(); + qpim_mroute_socket_fd = -1; + + zassert(PIM_MROUTE_IS_DISABLED); + + return 0; +} + +/* + For each network interface (e.g., physical or a virtual tunnel) that + would be used for multicast forwarding, a corresponding multicast + interface must be added to the kernel. + */ +int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) +{ + struct vifctl vc; + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + memset(&vc, 0, sizeof(vc)); + vc.vifc_vifi = vif_index; + vc.vifc_flags = 0; + vc.vifc_threshold = PIM_MROUTE_MIN_TTL; + vc.vifc_rate_limit = 0; + memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr)); + +#ifdef PIM_DVMRP_TUNNEL + if (vc.vifc_flags & VIFF_TUNNEL) { + memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr)); + } +#endif + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); + if (err) { + char ifaddr_str[100]; + int e = errno; + + pim_inet4_dump("", ifaddr, ifaddr_str, sizeof(ifaddr_str)); + + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, vif_index, ifaddr_str, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} + +int pim_mroute_del_vif(int vif_index) +{ + struct vifctl vc; + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + memset(&vc, 0, sizeof(vc)); + vc.vifc_vifi = vif_index; + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc)); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, vif_index, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} + +int pim_mroute_add(struct mfcctl *mc) +{ + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, + mc, sizeof(*mc)); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} + +int pim_mroute_del(struct mfcctl *mc) +{ + int err; + + if (PIM_MROUTE_IS_DISABLED) { + zlog_warn("%s: global multicast is disabled", + __PRETTY_FUNCTION__); + return -1; + } + + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc)); + if (err) { + int e = errno; + zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + qpim_mroute_socket_fd, + e, strerror(e)); + errno = e; + return -2; + } + + return 0; +} -- cgit v1.2.3 From 40b0f20733365209141491e3c45ebaf63979d835 Mon Sep 17 00:00:00 2001 From: Leonard Herve Date: Tue, 11 Aug 2009 15:45:26 -0300 Subject: [pim] pim commands added to vtysh --- pimd/pim_mroute.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'pimd/pim_mroute.c') diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index f021abaa..48213b0b 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -22,6 +22,7 @@ #include #include "log.h" +#include "privs.h" #include "pimd.h" #include "pim_mroute.h" @@ -30,6 +31,9 @@ #include "pim_iface.h" #include "pim_macro.h" +/* GLOBAL VARS */ +extern struct zebra_privs_t pimd_privs; + static void mroute_read_on(void); static int pim_mroute_set(int fd, int enable) @@ -259,7 +263,16 @@ int pim_mroute_socket_enable() if (PIM_MROUTE_IS_ENABLED) return -1; + if ( pimd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("pim_mroute_socket_enable: could not raise privs, %s", + safe_strerror (errno) ); + fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + + if ( pimd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("pim_mroute_socket_enable: could not lower privs, %s", + safe_strerror (errno) ); + if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", errno, strerror(errno)); -- cgit v1.2.3 From 077339fc42d51afb3e936171d112b1da8519220a Mon Sep 17 00:00:00 2001 From: Everton Marques Date: Tue, 11 Aug 2009 15:48:02 -0300 Subject: [pim] Log physical interface up/down [pim] Replace strerror with safe_strerror [pim] Fix PIM socket removal from non-PIM interfaces [pim] show ip igmp querier: left-align Querier string [pim] Version up to 0.157 [pim] Recipe to re-sync with Quagga repository [pim] Build vtysh in development script --- pimd/pim_mroute.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'pimd/pim_mroute.c') diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 48213b0b..c76ba525 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -47,7 +47,7 @@ static int pim_mroute_set(int fd, int enable) int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, - fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, strerror(e)); + fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e)); errno = e; return -1; } @@ -209,7 +209,7 @@ static int mroute_read_msg(int fd) rd = read(fd, buf, sizeof(buf)); if (rd < 0) { zlog_warn("%s: failure reading fd=%d: errno=%d: %s", - __PRETTY_FUNCTION__, fd, errno, strerror(errno)); + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); return -2; } @@ -275,13 +275,13 @@ int pim_mroute_socket_enable() if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", - errno, strerror(errno)); + errno, safe_strerror(errno)); return -2; } if (pim_mroute_set(fd, 1)) { zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s", - fd, errno, strerror(errno)); + fd, errno, safe_strerror(errno)); close(fd); return -3; } @@ -302,13 +302,13 @@ int pim_mroute_socket_disable() if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s", - qpim_mroute_socket_fd, errno, strerror(errno)); + qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -2; } if (close(qpim_mroute_socket_fd)) { zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", - qpim_mroute_socket_fd, errno, strerror(errno)); + qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -3; } @@ -359,7 +359,7 @@ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, ifaddr_str, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } @@ -387,7 +387,7 @@ int pim_mroute_del_vif(int vif_index) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } @@ -412,7 +412,7 @@ int pim_mroute_add(struct mfcctl *mc) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } @@ -436,7 +436,7 @@ int pim_mroute_del(struct mfcctl *mc) zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, - e, strerror(e)); + e, safe_strerror(e)); errno = e; return -2; } -- cgit v1.2.3 From 168595ff42c4046167b0fbae2770c037c854abd0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 3 Feb 2010 16:29:37 +0100 Subject: dn42: pimd: vifctln support --- pimd/pim_mroute.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'pimd/pim_mroute.c') diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index c76ba525..f9c291dd 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -327,7 +327,7 @@ int pim_mroute_socket_disable() */ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) { - struct vifctl vc; + struct vifctl_ext vc; int err; if (PIM_MROUTE_IS_DISABLED) { @@ -337,11 +337,12 @@ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) } memset(&vc, 0, sizeof(vc)); - vc.vifc_vifi = vif_index; - vc.vifc_flags = 0; - vc.vifc_threshold = PIM_MROUTE_MIN_TTL; - vc.vifc_rate_limit = 0; - memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr)); + vc.vc.vifc_vifi = vif_index; + vc.vc.vifc_flags = 0; + vc.vc.vifc_threshold = PIM_MROUTE_MIN_TTL; + vc.vc.vifc_rate_limit = 0; + vc.ifindex = vif_index; + memcpy(&vc.vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vc.vifc_lcl_addr)); #ifdef PIM_DVMRP_TUNNEL if (vc.vifc_flags & VIFF_TUNNEL) { @@ -350,6 +351,8 @@ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) #endif err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); + if (err) + err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc.vc)); if (err) { char ifaddr_str[100]; int e = errno; -- cgit v1.2.3