3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
28 #include "pim_mroute.h"
31 #include "pim_iface.h"
32 #include "pim_macro.h"
35 extern struct zebra_privs_t pimd_privs;
37 static void mroute_read_on(void);
39 static int pim_mroute_set(int fd, int enable)
42 int opt = enable ? MRT_INIT : MRT_DONE;
43 socklen_t opt_len = sizeof(opt);
45 err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
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));
56 zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok",
57 __FILE__, __PRETTY_FUNCTION__,
64 int pim_mroute_msg(int fd, const char *buf, int buf_size)
66 struct interface *ifp;
67 const struct ip *ip_hdr;
68 const struct igmpmsg *msg;
73 ip_hdr = (const struct ip *) buf;
75 /* kernel upcall must have protocol=0 */
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);
85 msg = (const struct igmpmsg *) buf;
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?>";
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));
97 if (msg->im_msgtype == IGMPMSG_WRONGVIF) {
98 struct pim_ifchannel *ch;
99 struct pim_interface *pim_ifp;
102 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
104 RFC 4601 4.8.2. PIM-SSM-Only Routers
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
112 if (PIM_DEBUG_PIM_TRACE) {
113 zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
118 ifp ? ifp->name : "<ifname?>",
123 zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
125 src_str, grp_str, msg->im_vif);
131 zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s",
133 src_str, grp_str, ifp->name);
137 ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst);
139 zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s",
141 src_str, grp_str, ifp->name);
146 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
148 Transitions from NoInfo State
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).
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",
162 src_str, grp_str, ifp->name);
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",
169 src_str, grp_str, ifp->name);
173 if (assert_action_a1(ch)) {
174 zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
176 src_str, grp_str, ifp->name);
181 } /* IGMPMSG_WRONGVIF */
183 zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
191 ifp ? ifp->name : "<ifname?>",
197 static int mroute_read_msg(int fd)
199 const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg));
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);
209 rd = read(fd, buf, sizeof(buf));
211 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
212 __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
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);
222 return pim_mroute_msg(fd, buf, rd);
225 static int mroute_read(struct thread *t)
231 zassert(!THREAD_ARG(t));
234 zassert(fd == qpim_mroute_socket_fd);
236 result = mroute_read_msg(fd);
239 qpim_mroute_socket_reader = 0;
245 static void mroute_read_on()
247 zassert(!qpim_mroute_socket_reader);
248 zassert(PIM_MROUTE_IS_ENABLED);
250 THREAD_READ_ON(master, qpim_mroute_socket_reader,
251 mroute_read, 0, qpim_mroute_socket_fd);
254 static void mroute_read_off()
256 THREAD_OFF(qpim_mroute_socket_reader);
259 int pim_mroute_socket_enable()
263 if (PIM_MROUTE_IS_ENABLED)
266 if ( pimd_privs.change (ZPRIVS_RAISE) )
267 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
268 safe_strerror (errno) );
270 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
272 if ( pimd_privs.change (ZPRIVS_LOWER) )
273 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
274 safe_strerror (errno) );
277 zlog_warn("Could not create mroute socket: errno=%d: %s",
278 errno, safe_strerror(errno));
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));
289 qpim_mroute_socket_fd = fd;
290 qpim_mroute_socket_creation = pim_time_monotonic_sec();
293 zassert(PIM_MROUTE_IS_ENABLED);
298 int pim_mroute_socket_disable()
300 if (PIM_MROUTE_IS_DISABLED)
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));
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));
316 qpim_mroute_socket_fd = -1;
318 zassert(PIM_MROUTE_IS_DISABLED);
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.
328 int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr)
333 if (PIM_MROUTE_IS_DISABLED) {
334 zlog_warn("%s: global multicast is disabled",
335 __PRETTY_FUNCTION__);
339 memset(&vc, 0, sizeof(vc));
340 vc.vifc_vifi = vif_index;
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));
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));
352 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc));
354 char ifaddr_str[100];
357 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str));
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));
370 int pim_mroute_del_vif(int vif_index)
375 if (PIM_MROUTE_IS_DISABLED) {
376 zlog_warn("%s: global multicast is disabled",
377 __PRETTY_FUNCTION__);
381 memset(&vc, 0, sizeof(vc));
382 vc.vifc_vifi = vif_index;
384 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc));
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));
398 int pim_mroute_add(struct mfcctl *mc)
402 qpim_mroute_add_last = pim_time_monotonic_sec();
403 ++qpim_mroute_add_events;
405 if (PIM_MROUTE_IS_DISABLED) {
406 zlog_warn("%s: global multicast is disabled",
407 __PRETTY_FUNCTION__);
411 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
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));
426 int pim_mroute_del(struct mfcctl *mc)
430 qpim_mroute_del_last = pim_time_monotonic_sec();
431 ++qpim_mroute_del_events;
433 if (PIM_MROUTE_IS_DISABLED) {
434 zlog_warn("%s: global multicast is disabled",
435 __PRETTY_FUNCTION__);
439 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc));
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));