pim_mroute.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. PIM for Quagga
  3. Copyright (C) 2008 Everton da Silva Marques
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; see the file COPYING; if not, write to the
  14. Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  15. MA 02110-1301 USA
  16. $QuaggaId: $Format:%an, %ai, %h$ $
  17. */
  18. #include <zebra.h>
  19. #include "log.h"
  20. #include "privs.h"
  21. #include "pimd.h"
  22. #include "pim_mroute.h"
  23. #include "pim_str.h"
  24. #include "pim_time.h"
  25. #include "pim_iface.h"
  26. #include "pim_macro.h"
  27. /* GLOBAL VARS */
  28. extern struct zebra_privs_t pimd_privs;
  29. static void mroute_read_on(void);
  30. static int pim_mroute_set(int fd, int enable)
  31. {
  32. int err;
  33. int opt = enable ? MRT_INIT : MRT_DONE;
  34. socklen_t opt_len = sizeof(opt);
  35. err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
  36. if (err) {
  37. int e = errno;
  38. zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
  39. __FILE__, __PRETTY_FUNCTION__,
  40. fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e));
  41. errno = e;
  42. return -1;
  43. }
  44. #if 0
  45. zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok",
  46. __FILE__, __PRETTY_FUNCTION__,
  47. fd, opt);
  48. #endif
  49. return 0;
  50. }
  51. int pim_mroute_msg(int fd, const char *buf, int buf_size)
  52. {
  53. struct interface *ifp;
  54. const struct ip *ip_hdr;
  55. const struct igmpmsg *msg;
  56. const char *upcall;
  57. char src_str[100];
  58. char grp_str[100];
  59. ip_hdr = (const struct ip *) buf;
  60. /* kernel upcall must have protocol=0 */
  61. if (ip_hdr->ip_p) {
  62. /* this is not a kernel upcall */
  63. #ifdef PIM_UNEXPECTED_KERNEL_UPCALL
  64. zlog_warn("%s: not a kernel upcall proto=%d msg_size=%d",
  65. __PRETTY_FUNCTION__, ip_hdr->ip_p, buf_size);
  66. #endif
  67. return 0;
  68. }
  69. msg = (const struct igmpmsg *) buf;
  70. switch (msg->im_msgtype) {
  71. case IGMPMSG_NOCACHE: upcall = "NOCACHE"; break;
  72. case IGMPMSG_WRONGVIF: upcall = "WRONGVIF"; break;
  73. case IGMPMSG_WHOLEPKT: upcall = "WHOLEPKT"; break;
  74. default: upcall = "<unknown_upcall?>";
  75. }
  76. ifp = pim_if_find_by_vif_index(msg->im_vif);
  77. pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
  78. pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
  79. if (msg->im_msgtype == IGMPMSG_WRONGVIF) {
  80. struct pim_ifchannel *ch;
  81. struct pim_interface *pim_ifp;
  82. /*
  83. Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
  84. RFC 4601 4.8.2. PIM-SSM-Only Routers
  85. iif is the incoming interface of the packet.
  86. if (iif is in inherited_olist(S,G)) {
  87. send Assert(S,G) on iif
  88. }
  89. */
  90. if (PIM_DEBUG_PIM_TRACE) {
  91. zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
  92. __PRETTY_FUNCTION__,
  93. fd,
  94. src_str,
  95. grp_str,
  96. ifp ? ifp->name : "<ifname?>",
  97. msg->im_vif);
  98. }
  99. if (!ifp) {
  100. zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
  101. __PRETTY_FUNCTION__,
  102. src_str, grp_str, msg->im_vif);
  103. return -1;
  104. }
  105. pim_ifp = ifp->info;
  106. if (!pim_ifp) {
  107. zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s",
  108. __PRETTY_FUNCTION__,
  109. src_str, grp_str, ifp->name);
  110. return -2;
  111. }
  112. ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst);
  113. if (!ch) {
  114. zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s",
  115. __PRETTY_FUNCTION__,
  116. src_str, grp_str, ifp->name);
  117. return -3;
  118. }
  119. /*
  120. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  121. Transitions from NoInfo State
  122. An (S,G) data packet arrives on interface I, AND
  123. CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
  124. downstream interface that is in our (S,G) outgoing interface
  125. list. We optimistically assume that we will be the assert
  126. winner for this (S,G), and so we transition to the "I am Assert
  127. Winner" state and perform Actions A1 (below), which will
  128. initiate the assert negotiation for (S,G).
  129. */
  130. if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
  131. zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s",
  132. __PRETTY_FUNCTION__,
  133. src_str, grp_str, ifp->name);
  134. return -4;
  135. }
  136. if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
  137. zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel",
  138. __PRETTY_FUNCTION__,
  139. src_str, grp_str, ifp->name);
  140. return -5;
  141. }
  142. if (assert_action_a1(ch)) {
  143. zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
  144. __PRETTY_FUNCTION__,
  145. src_str, grp_str, ifp->name);
  146. return -6;
  147. }
  148. return 0;
  149. } /* IGMPMSG_WRONGVIF */
  150. zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
  151. __PRETTY_FUNCTION__,
  152. upcall,
  153. msg->im_msgtype,
  154. ip_hdr->ip_p,
  155. fd,
  156. src_str,
  157. grp_str,
  158. ifp ? ifp->name : "<ifname?>",
  159. msg->im_vif);
  160. return 0;
  161. }
  162. static int mroute_read_msg(int fd)
  163. {
  164. const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg));
  165. char buf[1000];
  166. int rd;
  167. if (((int) sizeof(buf)) < msg_min_size) {
  168. zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d",
  169. __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size);
  170. return -1;
  171. }
  172. rd = read(fd, buf, sizeof(buf));
  173. if (rd < 0) {
  174. zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
  175. __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
  176. return -2;
  177. }
  178. if (rd < msg_min_size) {
  179. zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d",
  180. __PRETTY_FUNCTION__, fd, rd, msg_min_size);
  181. return -3;
  182. }
  183. return pim_mroute_msg(fd, buf, rd);
  184. }
  185. static int mroute_read(struct thread *t)
  186. {
  187. int fd;
  188. int result;
  189. zassert(t);
  190. zassert(!THREAD_ARG(t));
  191. fd = THREAD_FD(t);
  192. zassert(fd == qpim_mroute_socket_fd);
  193. result = mroute_read_msg(fd);
  194. /* Keep reading */
  195. qpim_mroute_socket_reader = 0;
  196. mroute_read_on();
  197. return result;
  198. }
  199. static void mroute_read_on()
  200. {
  201. zassert(!qpim_mroute_socket_reader);
  202. zassert(PIM_MROUTE_IS_ENABLED);
  203. THREAD_READ_ON(master, qpim_mroute_socket_reader,
  204. mroute_read, 0, qpim_mroute_socket_fd);
  205. }
  206. static void mroute_read_off()
  207. {
  208. THREAD_OFF(qpim_mroute_socket_reader);
  209. }
  210. int pim_mroute_socket_enable()
  211. {
  212. int fd;
  213. if (PIM_MROUTE_IS_ENABLED)
  214. return -1;
  215. if ( pimd_privs.change (ZPRIVS_RAISE) )
  216. zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
  217. safe_strerror (errno) );
  218. fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
  219. if ( pimd_privs.change (ZPRIVS_LOWER) )
  220. zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
  221. safe_strerror (errno) );
  222. if (fd < 0) {
  223. zlog_warn("Could not create mroute socket: errno=%d: %s",
  224. errno, safe_strerror(errno));
  225. return -2;
  226. }
  227. if (pim_mroute_set(fd, 1)) {
  228. zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
  229. fd, errno, safe_strerror(errno));
  230. close(fd);
  231. return -3;
  232. }
  233. qpim_mroute_socket_fd = fd;
  234. qpim_mroute_socket_creation = pim_time_monotonic_sec();
  235. mroute_read_on();
  236. zassert(PIM_MROUTE_IS_ENABLED);
  237. return 0;
  238. }
  239. int pim_mroute_socket_disable()
  240. {
  241. if (PIM_MROUTE_IS_DISABLED)
  242. return -1;
  243. if (pim_mroute_set(qpim_mroute_socket_fd, 0)) {
  244. zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
  245. qpim_mroute_socket_fd, errno, safe_strerror(errno));
  246. return -2;
  247. }
  248. if (close(qpim_mroute_socket_fd)) {
  249. zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
  250. qpim_mroute_socket_fd, errno, safe_strerror(errno));
  251. return -3;
  252. }
  253. mroute_read_off();
  254. qpim_mroute_socket_fd = -1;
  255. zassert(PIM_MROUTE_IS_DISABLED);
  256. return 0;
  257. }
  258. /*
  259. For each network interface (e.g., physical or a virtual tunnel) that
  260. would be used for multicast forwarding, a corresponding multicast
  261. interface must be added to the kernel.
  262. */
  263. int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr)
  264. {
  265. struct vifctl vc;
  266. int err;
  267. if (PIM_MROUTE_IS_DISABLED) {
  268. zlog_warn("%s: global multicast is disabled",
  269. __PRETTY_FUNCTION__);
  270. return -1;
  271. }
  272. memset(&vc, 0, sizeof(vc));
  273. vc.vifc_vifi = vif_index;
  274. vc.vifc_flags = 0;
  275. vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
  276. vc.vifc_rate_limit = 0;
  277. memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
  278. #ifdef PIM_DVMRP_TUNNEL
  279. if (vc.vifc_flags & VIFF_TUNNEL) {
  280. memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr));
  281. }
  282. #endif
  283. err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc));
  284. if (err) {
  285. char ifaddr_str[100];
  286. int e = errno;
  287. pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str));
  288. zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s",
  289. __FILE__, __PRETTY_FUNCTION__,
  290. qpim_mroute_socket_fd, vif_index, ifaddr_str,
  291. e, safe_strerror(e));
  292. errno = e;
  293. return -2;
  294. }
  295. return 0;
  296. }
  297. int pim_mroute_del_vif(int vif_index)
  298. {
  299. struct vifctl vc;
  300. int err;
  301. if (PIM_MROUTE_IS_DISABLED) {
  302. zlog_warn("%s: global multicast is disabled",
  303. __PRETTY_FUNCTION__);
  304. return -1;
  305. }
  306. memset(&vc, 0, sizeof(vc));
  307. vc.vifc_vifi = vif_index;
  308. err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc));
  309. if (err) {
  310. int e = errno;
  311. zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
  312. __FILE__, __PRETTY_FUNCTION__,
  313. qpim_mroute_socket_fd, vif_index,
  314. e, safe_strerror(e));
  315. errno = e;
  316. return -2;
  317. }
  318. return 0;
  319. }
  320. int pim_mroute_add(struct mfcctl *mc)
  321. {
  322. int err;
  323. qpim_mroute_add_last = pim_time_monotonic_sec();
  324. ++qpim_mroute_add_events;
  325. if (PIM_MROUTE_IS_DISABLED) {
  326. zlog_warn("%s: global multicast is disabled",
  327. __PRETTY_FUNCTION__);
  328. return -1;
  329. }
  330. err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
  331. mc, sizeof(*mc));
  332. if (err) {
  333. int e = errno;
  334. zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
  335. __FILE__, __PRETTY_FUNCTION__,
  336. qpim_mroute_socket_fd,
  337. e, safe_strerror(e));
  338. errno = e;
  339. return -2;
  340. }
  341. return 0;
  342. }
  343. int pim_mroute_del(struct mfcctl *mc)
  344. {
  345. int err;
  346. qpim_mroute_del_last = pim_time_monotonic_sec();
  347. ++qpim_mroute_del_events;
  348. if (PIM_MROUTE_IS_DISABLED) {
  349. zlog_warn("%s: global multicast is disabled",
  350. __PRETTY_FUNCTION__);
  351. return -1;
  352. }
  353. err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc));
  354. if (err) {
  355. int e = errno;
  356. zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
  357. __FILE__, __PRETTY_FUNCTION__,
  358. qpim_mroute_socket_fd,
  359. e, safe_strerror(e));
  360. errno = e;
  361. return -2;
  362. }
  363. return 0;
  364. }