]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_jp_agg.c
pimd: Join/Prune Aggregation
[mirror_frr.git] / pimd / pim_jp_agg.c
1 #include <zebra.h>
2
3 #include "linklist.h"
4 #include "log.h"
5
6 #include "pimd.h"
7 #include "pim_msg.h"
8 #include "pim_jp_agg.h"
9 #include "pim_join.h"
10 #include "pim_iface.h"
11
12 void
13 pim_jp_agg_group_list_free (struct pim_jp_agg_group *jag)
14 {
15 list_delete(jag->sources);
16
17 XFREE (MTYPE_PIM_JP_AGG_GROUP, jag);
18 }
19
20 static void
21 pim_jp_agg_src_free (struct pim_jp_sources *js)
22 {
23 /*
24 * When we are being called here, we know
25 * that the neighbor is going away start
26 * the normal j/p timer so that it can
27 * pick this shit back up when the
28 * nbr comes back alive
29 */
30 join_timer_start(js->up);
31 XFREE (MTYPE_PIM_JP_AGG_SOURCE, js);
32 }
33
34 int
35 pim_jp_agg_group_list_cmp (void *arg1, void *arg2)
36 {
37 const struct pim_jp_agg_group *jag1 = (const struct pim_jp_agg_group *)arg1;
38 const struct pim_jp_agg_group *jag2 = (const struct pim_jp_agg_group *)arg2;
39
40 if (jag1->group.s_addr < jag2->group.s_addr)
41 return -1;
42
43 if (jag1->group.s_addr > jag2->group.s_addr)
44 return 1;
45
46 return 0;
47 }
48
49 static int
50 pim_jp_agg_src_cmp (void *arg1, void *arg2)
51 {
52 const struct pim_jp_sources *js1 = (const struct pim_jp_sources *)arg1;
53 const struct pim_jp_sources *js2 = (const struct pim_jp_sources *)arg2;
54
55 if (js1->up->sg.src.s_addr < js2->up->sg.src.s_addr)
56 return -1;
57
58 if (js1->up->sg.src.s_addr > js2->up->sg.src.s_addr)
59 return 1;
60
61 return 0;
62 }
63
64 void
65 pim_jp_agg_clear_group (struct list *group)
66 {
67 struct listnode *node, *nnode;
68 struct pim_jp_agg_group *jag;
69
70 for (ALL_LIST_ELEMENTS(group, node, nnode, jag))
71 {
72 list_delete(jag->sources);
73 jag->sources = NULL;
74 listnode_delete(group, jag);
75 XFREE(MTYPE_PIM_JP_AGG_GROUP, jag);
76 }
77 }
78
79 static struct pim_iface_upstream_switch *
80 pim_jp_agg_get_interface_upstream_switch_list (struct pim_rpf *rpf)
81 {
82 struct pim_interface *pim_ifp = rpf->source_nexthop.interface->info;
83 struct pim_iface_upstream_switch *pius;
84 struct listnode *node, *nnode;
85
86 for (ALL_LIST_ELEMENTS(pim_ifp->upstream_switch_list, node, nnode, pius))
87 {
88 if (pius->address.s_addr == rpf->rpf_addr.u.prefix4.s_addr)
89 break;
90 }
91
92 if (!pius)
93 {
94 pius = XCALLOC(MTYPE_PIM_JP_AGG_GROUP, sizeof (struct pim_iface_upstream_switch));
95 pius->address.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
96 pius->us = list_new();
97 listnode_add (pim_ifp->upstream_switch_list, pius);
98 }
99
100 return pius;
101 }
102
103 void
104 pim_jp_agg_remove_group (struct list *group, struct pim_upstream *up)
105 {
106 struct listnode *node, *nnode;
107 struct pim_jp_agg_group *jag = NULL;
108 struct pim_jp_sources *js = NULL;
109
110 for (ALL_LIST_ELEMENTS(group, node, nnode, jag))
111 {
112 if (jag->group.s_addr == up->sg.grp.s_addr)
113 break;
114 }
115
116 if (!jag)
117 return;
118
119 for (ALL_LIST_ELEMENTS(jag->sources, node, nnode, js))
120 {
121 if (js->up == up)
122 break;
123 }
124
125 listnode_delete(jag->sources, js);
126
127 XFREE(MTYPE_PIM_JP_AGG_SOURCE, js);
128
129 if (jag->sources->count == 0)
130 {
131 list_delete(jag->sources);
132 listnode_delete(group, jag);
133 }
134 }
135
136 void
137 pim_jp_agg_add_group (struct list *group, struct pim_upstream *up, bool is_join)
138 {
139 struct listnode *node, *nnode;
140 struct pim_jp_agg_group *jag = NULL;
141 struct pim_jp_sources *js;
142
143 for (ALL_LIST_ELEMENTS(group, node, nnode, jag))
144 {
145 if (jag->group.s_addr == up->sg.grp.s_addr)
146 break;
147 }
148
149 if (!jag)
150 {
151 jag = XCALLOC(MTYPE_PIM_JP_AGG_GROUP, sizeof (struct pim_jp_agg_group));
152 jag->group.s_addr = up->sg.grp.s_addr;
153 jag->sources = list_new();
154 jag->sources->cmp = pim_jp_agg_src_cmp;
155 jag->sources->del = (void (*)(void *))pim_jp_agg_src_free;
156 listnode_add (group, jag);
157 }
158
159 js = XCALLOC(MTYPE_PIM_JP_AGG_SOURCE, sizeof (struct pim_jp_sources));
160 js->up = up;
161 js->is_join = is_join;
162
163 listnode_add (jag->sources, js);
164 }
165
166 void
167 pim_jp_agg_switch_interface (struct pim_rpf *orpf,
168 struct pim_rpf *nrpf,
169 struct pim_upstream *up)
170 {
171 struct pim_iface_upstream_switch *opius;
172 struct pim_iface_upstream_switch *npius;
173
174 opius = pim_jp_agg_get_interface_upstream_switch_list(orpf);
175 npius = pim_jp_agg_get_interface_upstream_switch_list(nrpf);
176
177 /*
178 * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
179 *
180 * Transitions from Joined State
181 *
182 * RPF'(S,G) changes not due to an Assert
183 *
184 * The upstream (S,G) state machine remains in Joined
185 * state. Send Join(S,G) to the new upstream neighbor, which is
186 * the new value of RPF'(S,G). Send Prune(S,G) to the old
187 * upstream neighbor, which is the old value of RPF'(S,G). Set
188 * the Join Timer (JT) to expire after t_periodic seconds.
189 */
190
191 /* send Prune(S,G) to the old upstream neighbor */
192 pim_jp_agg_add_group (opius->us, up, false);
193
194 /* send Join(S,G) to the current upstream neighbor */
195 pim_jp_agg_add_group (npius->us, up, true);
196
197 }
198
199
200 void
201 pim_jp_agg_single_upstream_send (struct pim_rpf *rpf,
202 struct pim_upstream *up,
203 bool is_join)
204 {
205 static struct list *groups = NULL;
206 static struct pim_jp_agg_group jag;
207 static struct pim_jp_sources js;
208
209 static bool first = true;
210
211 if (first)
212 {
213 groups = list_new();
214
215 jag.sources = list_new();
216
217 listnode_add(groups, &jag);
218 listnode_add(jag.sources, &js);
219
220 first = false;
221 }
222
223 jag.group.s_addr = up->sg.grp.s_addr;
224 js.up = up;
225 js.is_join = is_join;
226
227 pim_joinprune_send(rpf, groups);
228 }