IGMP: proxy device
[vpp.git] / src / plugins / igmp / igmp_group.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <igmp/igmp_group.h>
19 #include <igmp/igmp.h>
20
21 void
22 igmp_group_free_all_srcs (igmp_group_t * group)
23 {
24   igmp_src_t *src;
25
26   /* *INDENT-OFF* */
27   FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
28     ({
29       igmp_src_free(src);
30     }));
31   /* *INDENT-ON* */
32
33   hash_free (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE]);
34   hash_free (group->igmp_src_by_key[IGMP_FILTER_MODE_EXCLUDE]);
35 }
36
37 void
38 igmp_group_src_remove (igmp_group_t * group, igmp_src_t * src)
39 {
40   hash_unset_mem (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE], src->key);
41   hash_unset_mem (group->igmp_src_by_key[IGMP_FILTER_MODE_EXCLUDE], src->key);
42 }
43
44 igmp_src_t *
45 igmp_group_src_update (igmp_group_t * group,
46                        const igmp_key_t * skey, igmp_mode_t mode)
47 {
48   igmp_src_t *src;
49
50   src = igmp_src_lookup (group, skey);
51
52   if (NULL == src)
53     {
54       src = igmp_src_alloc (igmp_group_index (group), skey, mode);
55
56       hash_set_mem (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE],
57                     src->key, igmp_src_index (src));
58     }
59   else
60     {
61       igmp_src_refresh (src);
62     }
63
64   return (src);
65 }
66
67 void
68 igmp_group_clear (igmp_group_t * group)
69 {
70   igmp_config_t *config;
71   u32 ii;
72
73   ASSERT (group);
74
75   config = igmp_config_get (group->config);
76
77   /* If interface is in ROUTER mode and IGMP proxy is enabled
78    * remove mfib path.
79    */
80   if (config->mode == IGMP_MODE_ROUTER)
81     {
82       igmp_proxy_device_mfib_path_add_del (group, /* add */ 0);
83     }
84
85   IGMP_DBG ("clear-group: %U %U",
86             format_igmp_key, group->key,
87             format_vnet_sw_if_index_name,
88             vnet_get_main (), config->sw_if_index);
89
90   igmp_group_free_all_srcs (group);
91
92   for (ii = 0; ii < IGMP_GROUP_N_TIMERS; ii++)
93     {
94       igmp_timer_retire (&group->timers[ii]);
95     }
96
97   hash_unset_mem (config->igmp_group_by_key, group->key);
98   clib_mem_free (group->key);
99   pool_put (igmp_main.groups, group);
100 }
101
102 igmp_group_t *
103 igmp_group_alloc (igmp_config_t * config,
104                   const igmp_key_t * gkey, igmp_filter_mode_t mode)
105 {
106   igmp_main_t *im = &igmp_main;
107   igmp_group_t *group;
108   u32 ii;
109
110   IGMP_DBG ("new-group: %U", format_igmp_key, gkey);
111   pool_get (im->groups, group);
112   memset (group, 0, sizeof (igmp_group_t));
113   group->key = clib_mem_alloc (sizeof (igmp_key_t));
114   clib_memcpy (group->key, gkey, sizeof (igmp_key_t));
115   group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE] =
116     hash_create_mem (0, sizeof (igmp_key_t), sizeof (uword));
117   group->igmp_src_by_key[IGMP_FILTER_MODE_EXCLUDE] =
118     hash_create_mem (0, sizeof (igmp_key_t), sizeof (uword));
119   group->router_filter_mode = mode;
120   group->config = igmp_config_index (config);
121   group->n_reports_sent = 0;
122
123   for (ii = 0; ii < IGMP_GROUP_N_TIMERS; ii++)
124     group->timers[ii] = IGMP_TIMER_ID_INVALID;
125
126   hash_set_mem (config->igmp_group_by_key, group->key, group - im->groups);
127
128   /* If interface is in ROUTER mode and IGMP proxy is enabled
129    * add mfib path.
130    */
131   if (config->mode == IGMP_MODE_ROUTER)
132     {
133       igmp_proxy_device_mfib_path_add_del (group, /* add */ 1);
134     }
135
136   return (group);
137 }
138
139 /**
140  * the set of present sources minus the new set
141  */
142 ip46_address_t *
143 igmp_group_present_minus_new (igmp_group_t * group,
144                               igmp_filter_mode_t mode,
145                               const ip46_address_t * saddrs)
146 {
147   const ip46_address_t *s1;
148   ip46_address_t *pmn;
149   igmp_src_t *src;
150   u32 found;
151
152   pmn = NULL;
153
154   /* *INDENT-OFF* */
155   if (0 == vec_len(saddrs))
156     {
157       FOR_EACH_SRC(src, group, mode,
158         ({
159           vec_add1(pmn, *src->key);
160         }));
161     }
162   else
163     {
164       FOR_EACH_SRC(src, group, mode,
165         ({
166           found = 0;
167           vec_foreach(s1, saddrs)
168             {
169               if (ip46_address_is_equal(s1, src->key))
170                 {
171                   found = 1;
172                   break;
173                 }
174             }
175
176           if (!found)
177             vec_add1(pmn, *src->key);
178         }));
179     }
180   /* *INDENT-ON* */
181
182   return (pmn);
183 }
184
185 /**
186  * the set of new sources minus the present set
187  */
188 ip46_address_t *
189 igmp_group_new_minus_present (igmp_group_t * group,
190                               igmp_filter_mode_t mode,
191                               const ip46_address_t * saddrs)
192 {
193   const ip46_address_t *s1;
194   ip46_address_t *npm;
195   igmp_src_t *src;
196   u32 found;
197
198   npm = NULL;
199
200   /* *INDENT-OFF* */
201   vec_foreach(s1, saddrs)
202     {
203       found = 0;
204       FOR_EACH_SRC(src, group, mode,
205         ({
206           if (ip46_address_is_equal(s1, src->key))
207             {
208               found = 1;
209               break;
210             }
211         }));
212
213       if (!found)
214         vec_add1(npm, *s1);
215     }
216   /* *INDENT-ON* */
217
218   return (npm);
219 }
220
221 ip46_address_t *
222 igmp_group_new_intersect_present (igmp_group_t * group,
223                                   igmp_filter_mode_t mode,
224                                   const ip46_address_t * saddrs)
225 {
226   ip46_address_t *intersect;
227   const ip46_address_t *s1;
228   igmp_src_t *src;
229
230   intersect = NULL;
231
232   /* *INDENT-OFF* */
233   FOR_EACH_SRC(src, group, mode,
234     ({
235       vec_foreach(s1, saddrs)
236         {
237           if (s1->ip4.as_u32 == src->key->ip4.as_u32)
238             {
239               vec_add1(intersect, *s1);
240               break;
241             }
242         }
243     }));
244   /* *INDENT-ON* */
245
246   return (intersect);
247 }
248
249 u32
250 igmp_group_n_srcs (const igmp_group_t * group, igmp_filter_mode_t mode)
251 {
252   return (hash_elts (group->igmp_src_by_key[mode]));
253 }
254
255
256 igmp_src_t *
257 igmp_src_lookup (igmp_group_t * group, const igmp_key_t * key)
258 {
259   uword *p;
260   igmp_src_t *src = NULL;
261   if (!group)
262     return NULL;
263
264   p = hash_get_mem (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE], key);
265   if (p)
266     src = vec_elt_at_index (igmp_main.srcs, p[0]);
267
268   return src;
269 }
270
271 u32
272 igmp_group_index (const igmp_group_t * g)
273 {
274   return (g - igmp_main.groups);
275 }
276
277 igmp_group_t *
278 igmp_group_get (u32 index)
279 {
280   return (pool_elt_at_index (igmp_main.groups, index));
281 }
282
283 /*
284  * fd.io coding-style-patch-verification: ON
285  *
286  * Local Variables:
287  * eval: (c-set-style "gnu")
288  * End:
289  */