1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* pim_bsm.h: PIM BSM handling related
*
* Copyright (C) 2018-19 Vmware, Inc.
* Saravanan K
*/
#ifndef __PIM_BSM_H__
#define __PIM_BSM_H__
#include "if.h"
#include "vty.h"
#include "typesafe.h"
#include "table.h"
#include "pim_rp.h"
#include "pim_msg.h"
/* Defines */
#define PIM_GBL_SZ_ID 0 /* global scope zone id set to 0 */
#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
/* number of times to include rp-count = 0 ranges */
#define PIM_BSR_DEAD_COUNT 3
#define PIM_CRP_ADV_TRIGCOUNT 3
#define PIM_CRP_ADV_INTERVAL 60
#define PIM_CRP_HOLDTIME 150
/* These structures are only encoded IPv4 specific */
#define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr)
#define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo)
#define PIM_BSM_RP_LEN sizeof(struct bsmmsg_rpinfo)
#define PIM_MIN_BSM_LEN \
(PIM_HDR_LEN + PIM_BSM_HDR_LEN + PIM_BSM_GRP_LEN + PIM_BSM_RP_LEN)
/* Datastructures
* ==============
*/
/* BSR states
*
* Candidate BSR starts at BSR_PENDING, moves to AP or E depending on
* loss/win. Will never go into AA (because in that case it'd become BSR
* itself.)
*
* Non-Candidate BSR starts at NO_INFO, moves to AP & AA depending on
* a BSR being available or not.
*/
enum bsr_state {
NO_INFO = 0,
ACCEPT_ANY,
ACCEPT_PREFERRED, /* = same as C-BSR if candidate */
BSR_PENDING,
BSR_ELECTED,
};
enum cand_addr {
CAND_ADDR_LO = 0,
CAND_ADDR_ANY,
CAND_ADDR_IFACE,
CAND_ADDR_EXPLICIT,
};
/* used separately for Cand-RP and Cand-BSR */
struct cand_addrsel {
bool cfg_enable;
enum cand_addr cfg_mode : 8;
/* only valid for mode==CAND_ADDR_IFACE */
char cfg_ifname[IFNAMSIZ];
/* only valid for mode==CAND_ADDR_EXPLICIT */
pim_addr cfg_addr;
/* running state updated based on above on zebra events */
pim_addr run_addr;
bool run;
};
PREDECL_DLIST(bsm_frags);
PREDECL_RBTREE_UNIQ(cand_rp_groups);
/* n*m "table" accessed both by-RP and by-group */
PREDECL_RBTREE_UNIQ(bsr_crp_rps);
PREDECL_RBTREE_UNIQ(bsr_crp_groups);
PREDECL_RBTREE_UNIQ(bsr_crp_rp_groups);
PREDECL_RBTREE_UNIQ(bsr_crp_group_rps);
/* BSM scope - bsm processing is per scope */
struct bsm_scope {
int sz_id; /* scope zone id */
enum bsr_state state; /* BSR state */
bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
pim_addr current_bsr; /* current elected BSR for the sz */
uint32_t current_bsr_prio; /* current BSR priority */
int64_t current_bsr_first_ts; /* current BSR elected time */
int64_t current_bsr_last_ts; /* Last BSM received from E-BSR */
uint16_t bsm_frag_tag; /* Last received frag tag from E-BSR */
uint8_t hashMasklen; /* Mask in hash calc RFC 7761 4.7.2 */
struct pim_instance *pim; /* Back pointer to pim instance */
/* current set of fragments for forwarding */
struct bsm_frags_head bsm_frags[1];
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
struct event *bs_timer; /* Boot strap timer */
/* Candidate BSR config */
struct cand_addrsel bsr_addrsel;
uint8_t cand_bsr_prio;
/* Candidate BSR state */
uint8_t current_cand_bsr_prio;
/* if nothing changed from Cand-RP data we received, less work... */
bool elec_rp_data_changed;
/* data that the E-BSR keeps - not to be confused with Candidate-RP
* stuff below. These two here are the info about all the Cand-RPs
* that we as a BSR received information for in Cand-RP-adv packets.
*/
struct bsr_crp_rps_head ebsr_rps[1];
struct bsr_crp_groups_head ebsr_groups[1];
/* set if we have any group ranges where we're currently advertising
* rp-count = 0 (includes both ranges without any RPs as well as
* ranges with only NHT-unreachable RPs)
*/
bool ebsr_have_dead_pending;
unsigned int changed_bsm_trigger;
struct event *t_ebsr_regen_bsm;
/* Candidate RP config */
struct cand_addrsel cand_rp_addrsel;
uint8_t cand_rp_prio;
unsigned int cand_rp_interval; /* default: PIM_CRP_ADV_INTERVAL=60 */
/* holdtime is not configurable, always 2.5 * interval. */
struct cand_rp_groups_head cand_rp_groups[1];
/* Candidate RP state */
int unicast_sock;
struct event *unicast_read;
struct event *cand_rp_adv_timer;
unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */
/* for sending holdtime=0 zap */
pim_addr cand_rp_prev_addr;
};
struct cand_rp_group {
struct cand_rp_groups_item item;
prefix_pim p;
};
struct bsr_crp_group {
struct bsr_crp_groups_item item;
prefix_pim range;
struct bsr_crp_group_rps_head rps[1];
size_t n_selected;
bool deleted_selected : 1;
/* number of times we've advertised this range with rp-count = 0 */
unsigned int dead_count;
};
struct bsr_crp_rp {
struct bsr_crp_rps_item item;
pim_addr addr;
struct bsr_crp_rp_groups_head groups[1];
struct bsm_scope *scope;
struct event *t_hold;
time_t seen_first;
time_t seen_last;
uint16_t holdtime;
uint8_t prio;
bool nht_ok;
};
/* "n * m" RP<->Group tie-in */
struct bsr_crp_item {
struct bsr_crp_rp_groups_item r_g_item;
struct bsr_crp_group_rps_item g_r_item;
struct bsr_crp_group *group;
struct bsr_crp_rp *rp;
bool selected : 1;
};
/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
* This is used for forwarding to new neighbors or restarting mcast routers
*/
struct bsm_frag {
struct bsm_frags_item item;
uint32_t size; /* size of the packet */
uint8_t data[0]; /* Actual packet (dyn size) */
};
DECLARE_DLIST(bsm_frags, struct bsm_frag, item);
PREDECL_SORTLIST_UNIQ(bsm_rpinfos);
/* This is the group node of the bsrp table in scope.
* this node maintains the list of rp for the group.
*/
struct bsgrp_node {
struct prefix group; /* Group range */
struct bsm_scope *scope; /* Back ptr to scope */
/* RPs advertised by BSR, and temporary list while receiving new set */
struct bsm_rpinfos_head bsrp_list[1];
struct bsm_rpinfos_head partial_bsrp_list[1];
int pend_rp_cnt; /* Total RP - Received RP */
uint16_t frag_tag; /* frag tag to identify the fragment */
};
/* Items on [partial_]bsrp_list above.
* Holds info of each candidate RP received for the bsgrp_node's prefix.
*/
struct bsm_rpinfo {
struct bsm_rpinfos_item item;
uint32_t hash; /* Hash Value as per RFC 7761 4.7.2 */
uint32_t elapse_time; /* upd at expiry of elected RP node */
uint16_t rp_prio; /* RP priority */
uint16_t rp_holdtime; /* RP holdtime - g2rp timer value */
pim_addr rp_address; /* RP Address */
struct bsgrp_node *bsgrp_node; /* Back ptr to bsgrp_node */
struct event *g2rp_timer; /* Run only for elected RP node */
};
extern int pim_bsm_rpinfo_cmp(const struct bsm_rpinfo *a,
const struct bsm_rpinfo *b);
DECLARE_SORTLIST_UNIQ(bsm_rpinfos, struct bsm_rpinfo, item, pim_bsm_rpinfo_cmp);
/* Structures to extract Bootstrap Message header and Grp to RP Mappings
* =====================================================================
* BSM Format:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |PIM Ver| Type |N| Reserved | Checksum | PIM HDR
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Fragment Tag | Hash Mask Len | BSR Priority | BS HDR(1)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | BSR Address (Encoded-Unicast format) | BS HDR(2)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Group Address 1 (Encoded-Group format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Count 1 | Frag RP Cnt 1 | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Address 1 (Encoded-Unicast format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP1 Holdtime | RP1 Priority | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Address 2 (Encoded-Unicast format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP2 Holdtime | RP2 Priority | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | . |
* | . |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Address m (Encoded-Unicast format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RPm Holdtime | RPm Priority | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Group Address 2 (Encoded-Group format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | . |
* | . |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Group Address n (Encoded-Group format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Count n | Frag RP Cnt n | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Address 1 (Encoded-Unicast format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP1 Holdtime | RP1 Priority | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Address 2 (Encoded-Unicast format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP2 Holdtime | RP2 Priority | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | . |
* | . |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RP Address m (Encoded-Unicast format) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RPm Holdtime | RPm Priority | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct bsm_hdr {
uint16_t frag_tag;
uint8_t hm_len;
uint8_t bsr_prio;
#if PIM_IPV == 4
struct pim_encoded_ipv4_unicast bsr_addr;
#else
struct pim_encoded_ipv6_unicast bsr_addr;
#endif
} __attribute__((packed));
struct bsmmsg_grpinfo {
#if PIM_IPV == 4
struct pim_encoded_group_ipv4 group;
#else
struct pim_encoded_group_ipv6 group;
#endif
uint8_t rp_count;
uint8_t frag_rp_count;
uint16_t reserved;
} __attribute__((packed));
struct bsmmsg_rpinfo {
#if PIM_IPV == 4
struct pim_encoded_ipv4_unicast rpaddr;
#else
struct pim_encoded_ipv6_unicast rpaddr;
#endif
uint16_t rp_holdtime;
uint8_t rp_pri;
uint8_t reserved;
} __attribute__((packed));
struct cand_rp_msg {
uint8_t prefix_cnt;
uint8_t rp_prio;
uint16_t rp_holdtime;
pim_encoded_unicast rp_addr;
pim_encoded_group groups[0];
} __attribute__((packed));
/* API */
void pim_bsm_proc_init(struct pim_instance *pim);
void pim_bsm_proc_free(struct pim_instance *pim);
void pim_bsm_clear(struct pim_instance *pim);
void pim_bsm_write_config(struct vty *vty, struct interface *ifp);
int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
uint32_t buf_size, bool no_fwd);
bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp);
struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
struct prefix *grp);
void pim_bsm_generate(struct bsm_scope *scope);
void pim_bsm_changed(struct bsm_scope *scope);
void pim_bsm_sent(struct bsm_scope *scope);
void pim_bsm_frags_free(struct bsm_scope *scope);
bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
int buflen, uint16_t bsm_frag_tag);
void pim_cand_bsr_apply(struct bsm_scope *scope);
void pim_cand_rp_apply(struct bsm_scope *scope);
void pim_cand_rp_trigger(struct bsm_scope *scope);
void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p);
void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p);
void pim_cand_addrs_changed(void);
int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
uint32_t buf_size);
struct pim_nexthop_cache;
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
void pim_crp_db_clear(struct bsm_scope *scope);
int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope, bool json);
int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope, bool json);
int pim_cand_config_write(struct pim_instance *pim, struct vty *vty);
DECLARE_MTYPE(PIM_BSM_FRAG);
DECLARE_MTYPE(PIM_BSM_FRAG);
DECLARE_MTYPE(PIM_BSM_FRAG);
#endif
|