]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_static.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / pimd / pim_static.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
6250610a 2/*
896014f4
DL
3 * PIM for Quagga: add the ability to configure multicast static routes
4 * Copyright (C) 2014 Nathan Bahr, ATCorp
896014f4 5 */
6250610a 6
f91f89bc
DS
7#include <zebra.h>
8
9#include "vty.h"
744d91b3 10#include "if.h"
9867746a
DS
11#include "log.h"
12#include "memory.h"
13#include "linklist.h"
f91f89bc 14
9867746a 15#include "pimd.h"
993e3d8e 16#include "pim_instance.h"
9867746a 17#include "pim_oil.h"
6250610a
JAG
18#include "pim_static.h"
19#include "pim_time.h"
20#include "pim_str.h"
6250610a 21#include "pim_iface.h"
6250610a
JAG
22
23void pim_static_route_free(struct static_route *s_route)
24{
d62a17ae 25 XFREE(MTYPE_PIM_STATIC_ROUTE, s_route);
6250610a
JAG
26}
27
4d762f26 28static struct static_route *static_route_alloc(void)
6250610a 29{
2b57b948 30 return XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(struct static_route));
6250610a
JAG
31}
32
9981117a 33static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif,
f0d63d90
DL
34 pim_addr group,
35 pim_addr source)
6250610a 36{
d62a17ae 37 struct static_route *s_route;
38 s_route = static_route_alloc();
d62a17ae 39
40 s_route->group = group;
41 s_route->source = source;
42 s_route->iif = iif;
43 s_route->oif_ttls[oif] = 1;
44 s_route->c_oil.oil_ref_count = 1;
f0d63d90
DL
45 *oil_origin(&s_route->c_oil) = source;
46 *oil_mcastgrp(&s_route->c_oil) = group;
47 *oil_parent(&s_route->c_oil) = iif;
48 oil_if_set(&s_route->c_oil, oif, 1);
d62a17ae 49 s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec();
50
51 return s_route;
6250610a
JAG
52}
53
54
4e0bc0f0 55int pim_static_add(struct pim_instance *pim, struct interface *iif,
f0d63d90 56 struct interface *oif, pim_addr group, pim_addr source)
6250610a 57{
d62a17ae 58 struct listnode *node = NULL;
59 struct static_route *s_route = NULL;
60 struct static_route *original_s_route = NULL;
61 struct pim_interface *pim_iif = iif ? iif->info : NULL;
62 struct pim_interface *pim_oif = oif ? oif->info : NULL;
63 ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
64 ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
65
04b6c83d 66 if (!iif_index || !oif_index || iif_index == -1 || oif_index == -1) {
d62a17ae 67 zlog_warn(
68 "%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
5e81f5dd 69 __FILE__, __func__, iif_index, oif_index);
d62a17ae 70 return -2;
71 }
6250610a
JAG
72
73#ifdef PIM_ENFORCE_LOOPFREE_MFC
d62a17ae 74 if (iif_index == oif_index) {
75 /* looped MFC entry */
76 zlog_warn(
77 "%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
5e81f5dd 78 __FILE__, __func__, iif_index, oif_index);
d62a17ae 79 return -4;
80 }
6250610a 81#endif
096f7609 82 if (iif->vrf->vrf_id != oif->vrf->vrf_id) {
72ec4672
DS
83 return -3;
84 }
85
4e0bc0f0 86 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
90937e42
JAG
87 if (!pim_addr_cmp(s_route->group, group) &&
88 !pim_addr_cmp(s_route->source, source) &&
89 (s_route->iif == iif_index)) {
90
91 if (s_route->oif_ttls[oif_index]) {
d62a17ae 92 zlog_warn(
f0d63d90 93 "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
5e81f5dd 94 __FILE__, __func__, iif_index,
f0d63d90 95 oif_index, &group, &source);
d62a17ae 96 return -3;
97 }
98
99 /* Ok, from here on out we will be making changes to the
100 * s_route structure, but if
101 * for some reason we fail to commit these changes to
102 * the kernel, we want to be able
103 * restore the state of the list. So copy the node data
104 * and if need be, we can copy
105 * back if it fails.
106 */
107 original_s_route = static_route_alloc();
d62a17ae 108 memcpy(original_s_route, s_route,
109 sizeof(struct static_route));
110
111 /* Route exists and has the same input interface, but
112 * adding a new output interface */
90937e42
JAG
113 s_route->oif_ttls[oif_index] = 1;
114 oil_if_set(&s_route->c_oil, oif_index, 1);
115 s_route->c_oil.oif_creation[oif_index] =
116 pim_time_monotonic_sec();
117 ++s_route->c_oil.oil_ref_count;
d62a17ae 118 break;
119 }
120 }
121
122 /* If node is null then we reached the end of the list without finding a
123 * match */
124 if (!node) {
125 s_route = static_route_new(iif_index, oif_index, group, source);
4e0bc0f0 126 listnode_add(pim->static_routes, s_route);
d62a17ae 127 }
128
2e4e8571
DS
129 s_route->c_oil.pim = pim;
130
5e81f5dd 131 if (pim_static_mroute_add(&s_route->c_oil, __func__)) {
d62a17ae 132 zlog_warn(
f0d63d90
DL
133 "%s %s: Unable to add static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
134 __FILE__, __func__, iif_index, oif_index, &group,
135 &source);
d62a17ae 136
137 /* Need to put s_route back to the way it was */
138 if (original_s_route) {
139 memcpy(s_route, original_s_route,
140 sizeof(struct static_route));
141 } else {
142 /* we never stored off a copy, so it must have been a
143 * fresh new route */
4e0bc0f0 144 listnode_delete(pim->static_routes, s_route);
d62a17ae 145 pim_static_route_free(s_route);
146 }
147
148 if (original_s_route) {
149 pim_static_route_free(original_s_route);
150 }
151
152 return -1;
153 }
154
155 /* Make sure we free the memory for the route copy if used */
156 if (original_s_route) {
157 pim_static_route_free(original_s_route);
158 }
159
160 if (PIM_DEBUG_STATIC) {
d62a17ae 161 zlog_debug(
f0d63d90
DL
162 "%s: Static route added(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
163 __func__, iif_index, oif_index, &group,
164 &source);
d62a17ae 165 }
166
167 return 0;
6250610a
JAG
168}
169
4e0bc0f0 170int pim_static_del(struct pim_instance *pim, struct interface *iif,
f0d63d90 171 struct interface *oif, pim_addr group, pim_addr source)
6250610a 172{
d62a17ae 173 struct listnode *node = NULL;
174 struct listnode *nextnode = NULL;
175 struct static_route *s_route = NULL;
176 struct pim_interface *pim_iif = iif ? iif->info : 0;
177 struct pim_interface *pim_oif = oif ? oif->info : 0;
178 ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
179 ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
180
181 if (!iif_index || !oif_index) {
182 zlog_warn(
183 "%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
5e81f5dd 184 __FILE__, __func__, iif_index, oif_index);
d62a17ae 185 return -2;
186 }
187
4e0bc0f0 188 for (ALL_LIST_ELEMENTS(pim->static_routes, node, nextnode, s_route)) {
d62a17ae 189 if (s_route->iif == iif_index
f0d63d90
DL
190 && !pim_addr_cmp(s_route->group, group)
191 && !pim_addr_cmp(s_route->source, source)
d62a17ae 192 && s_route->oif_ttls[oif_index]) {
193 s_route->oif_ttls[oif_index] = 0;
f0d63d90 194 oil_if_set(&s_route->c_oil, oif_index, 0);
d62a17ae 195 --s_route->c_oil.oil_ref_count;
196
197 /* If there are no more outputs then delete the whole
198 * route, otherwise set the route with the new outputs
199 */
200 if (s_route->c_oil.oil_ref_count <= 0
5e81f5dd 201 ? pim_mroute_del(&s_route->c_oil, __func__)
69e3538c 202 : pim_static_mroute_add(&s_route->c_oil,
5e81f5dd 203 __func__)) {
d62a17ae 204 zlog_warn(
f0d63d90 205 "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
5e81f5dd 206 __FILE__, __func__, iif_index,
f0d63d90 207 oif_index, &group, &source);
d62a17ae 208
209 s_route->oif_ttls[oif_index] = 1;
f0d63d90 210 oil_if_set(&s_route->c_oil, oif_index, 1);
d62a17ae 211 ++s_route->c_oil.oil_ref_count;
212
213 return -1;
214 }
215
216 s_route->c_oil.oif_creation[oif_index] = 0;
217
218 if (s_route->c_oil.oil_ref_count <= 0) {
4e0bc0f0 219 listnode_delete(pim->static_routes, s_route);
d62a17ae 220 pim_static_route_free(s_route);
221 }
222
223 if (PIM_DEBUG_STATIC) {
d62a17ae 224 zlog_debug(
f0d63d90 225 "%s: Static route removed(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
5e81f5dd 226 __func__, iif_index, oif_index,
f0d63d90 227 &group, &source);
d62a17ae 228 }
229
230 break;
231 }
232 }
233
234 if (!node) {
d62a17ae 235 zlog_warn(
f0d63d90
DL
236 "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
237 __FILE__, __func__, iif_index, oif_index, &group,
238 &source);
d62a17ae 239 return -3;
240 }
241
242 return 0;
6250610a 243}
f91f89bc 244
64c86530 245int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
4e0bc0f0 246 struct interface *ifp)
f91f89bc 247{
d62a17ae 248 struct pim_interface *pim_ifp = ifp->info;
249 struct listnode *node;
250 struct static_route *sroute;
251 int count = 0;
d62a17ae 252
253 if (!pim_ifp)
254 return 0;
255
4e0bc0f0 256 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sroute)) {
d62a17ae 257 if (sroute->iif == pim_ifp->mroute_vif_index) {
258 int i;
259 for (i = 0; i < MAXVIFS; i++)
260 if (sroute->oif_ttls[i]) {
261 struct interface *oifp =
7cfc7bcf
DS
262 pim_if_find_by_vif_index(pim,
263 i);
f0d63d90 264 if (pim_addr_is_any(sroute->source))
d62a17ae 265 vty_out(vty,
d17b6892 266 " " PIM_AF_NAME " mroute %s %pPA\n",
f0d63d90 267 oifp->name, &sroute->group);
d62a17ae 268 else
269 vty_out(vty,
d17b6892 270 " " PIM_AF_NAME " mroute %s %pPA %pPA\n",
f0d63d90
DL
271 oifp->name, &sroute->group,
272 &sroute->source);
d62a17ae 273 count++;
274 }
275 }
276 }
277
278 return count;
f91f89bc 279}