]>
Commit | Line | Data |
---|---|---|
12e41d03 | 1 | /* |
896014f4 DL |
2 | * PIM for Quagga |
3 | * Copyright (C) 2008 Everton da Silva Marques | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; see the file COPYING; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
12e41d03 DL |
19 | |
20 | #include <zebra.h> | |
21 | ||
744d91b3 | 22 | #include "if.h" |
346cffe3 | 23 | #include "log.h" |
dfe43e25 DW |
24 | #include "prefix.h" |
25 | #include "vty.h" | |
26 | #include "plist.h" | |
744d91b3 | 27 | |
12e41d03 | 28 | #include "pimd.h" |
75a26779 | 29 | #include "pim_vty.h" |
12e41d03 DL |
30 | #include "pim_pim.h" |
31 | #include "pim_msg.h" | |
32 | #include "pim_util.h" | |
346cffe3 | 33 | #include "pim_str.h" |
7176984f | 34 | #include "pim_iface.h" |
75a26779 | 35 | #include "pim_rp.h" |
d67f268e | 36 | #include "pim_rpf.h" |
5637da05 | 37 | #include "pim_register.h" |
982bff89 | 38 | #include "pim_jp_agg.h" |
92b422f1 | 39 | #include "pim_oil.h" |
12e41d03 | 40 | |
d62a17ae | 41 | void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, |
42 | uint8_t pim_msg_type) | |
12e41d03 | 43 | { |
d62a17ae | 44 | struct pim_msg_header *header = (struct pim_msg_header *)pim_msg; |
45 | ||
46 | /* | |
47 | * Write header | |
48 | */ | |
49 | header->ver = PIM_PROTO_VERSION; | |
50 | header->type = pim_msg_type; | |
51 | header->reserved = 0; | |
52 | ||
53 | ||
54 | header->checksum = 0; | |
55 | /* | |
56 | * The checksum for Registers is done only on the first 8 bytes of the | |
57 | * packet, | |
58 | * including the PIM header and the next 4 bytes, excluding the data | |
59 | * packet portion | |
60 | */ | |
61 | if (pim_msg_type == PIM_MSG_TYPE_REGISTER) | |
62 | header->checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN); | |
63 | else | |
64 | header->checksum = in_cksum(pim_msg, pim_msg_size); | |
12e41d03 DL |
65 | } |
66 | ||
f8e7d799 | 67 | uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr) |
12e41d03 | 68 | { |
d62a17ae | 69 | buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ |
70 | buf[1] = '\0'; /* native encoding */ | |
71 | memcpy(buf + 2, &addr, sizeof(struct in_addr)); | |
12e41d03 | 72 | |
d62a17ae | 73 | return buf + PIM_ENCODED_IPV4_UCAST_SIZE; |
12e41d03 DL |
74 | } |
75 | ||
f8e7d799 | 76 | uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr) |
12e41d03 | 77 | { |
d62a17ae | 78 | buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ |
79 | buf[1] = '\0'; /* native encoding */ | |
80 | buf[2] = '\0'; /* reserved */ | |
81 | buf[3] = 32; /* mask len */ | |
82 | memcpy(buf + 4, &addr, sizeof(struct in_addr)); | |
12e41d03 | 83 | |
d62a17ae | 84 | return buf + PIM_ENCODED_IPV4_GROUP_SIZE; |
12e41d03 DL |
85 | } |
86 | ||
d62a17ae | 87 | uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr, |
88 | uint8_t bits) | |
12e41d03 | 89 | { |
d62a17ae | 90 | buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ |
91 | buf[1] = '\0'; /* native encoding */ | |
92 | buf[2] = bits; | |
93 | buf[3] = 32; /* mask len */ | |
94 | memcpy(buf + 4, &addr, sizeof(struct in_addr)); | |
12e41d03 | 95 | |
d62a17ae | 96 | return buf + PIM_ENCODED_IPV4_SOURCE_SIZE; |
12e41d03 | 97 | } |
346cffe3 | 98 | |
982bff89 DS |
99 | /* |
100 | * For the given 'struct pim_jp_sources' list | |
101 | * determine the size_t it would take up. | |
102 | */ | |
d62a17ae | 103 | size_t pim_msg_get_jp_group_size(struct list *sources) |
982bff89 | 104 | { |
d62a17ae | 105 | struct pim_jp_sources *js; |
106 | size_t size = 0; | |
107 | ||
9403d285 DS |
108 | if (!sources) |
109 | return 0; | |
110 | ||
d62a17ae | 111 | size += sizeof(struct pim_encoded_group_ipv4); |
112 | size += 4; // Joined sources (2) + Pruned Sources (2) | |
113 | ||
114 | size += sizeof(struct pim_encoded_source_ipv4) * sources->count; | |
115 | ||
116 | js = listgetdata(listhead(sources)); | |
117 | if (js && js->up->sg.src.s_addr == INADDR_ANY) { | |
118 | struct pim_upstream *child, *up; | |
119 | struct listnode *up_node; | |
120 | ||
121 | up = js->up; | |
122 | if (PIM_DEBUG_PIM_PACKETS) | |
123 | zlog_debug( | |
124 | "%s: Considering (%s) children for (S,G,rpt) prune", | |
125 | __PRETTY_FUNCTION__, up->sg_str); | |
126 | ||
127 | for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) { | |
128 | if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) { | |
129 | if (!pim_rpf_is_same(&up->rpf, &child->rpf)) { | |
130 | size += sizeof( | |
131 | struct pim_encoded_source_ipv4); | |
132 | PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( | |
133 | child->flags); | |
134 | if (PIM_DEBUG_PIM_PACKETS) | |
135 | zlog_debug( | |
136 | "%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message", | |
137 | __PRETTY_FUNCTION__, | |
138 | up->sg_str, | |
139 | child->sg_str); | |
140 | } else if (PIM_DEBUG_PIM_PACKETS) | |
141 | zlog_debug( | |
142 | "%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", | |
143 | __PRETTY_FUNCTION__, up->sg_str, | |
144 | child->sg_str); | |
145 | } else if (pim_upstream_is_sg_rpt(child)) { | |
146 | if (pim_upstream_empty_inherited_olist(child)) { | |
147 | size += sizeof( | |
148 | struct pim_encoded_source_ipv4); | |
149 | PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( | |
150 | child->flags); | |
151 | if (PIM_DEBUG_PIM_PACKETS) | |
152 | zlog_debug( | |
153 | "%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", | |
154 | __PRETTY_FUNCTION__, | |
155 | child->sg_str); | |
156 | } else if (!pim_rpf_is_same(&up->rpf, | |
157 | &child->rpf)) { | |
158 | size += sizeof( | |
159 | struct pim_encoded_source_ipv4); | |
160 | PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( | |
161 | child->flags); | |
162 | if (PIM_DEBUG_PIM_PACKETS) | |
163 | zlog_debug( | |
164 | "%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message", | |
165 | __PRETTY_FUNCTION__, | |
166 | up->sg_str, | |
167 | child->sg_str); | |
168 | } else if (PIM_DEBUG_PIM_PACKETS) | |
169 | zlog_debug( | |
170 | "%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message", | |
171 | __PRETTY_FUNCTION__, up->sg_str, | |
172 | child->sg_str); | |
173 | } else if (PIM_DEBUG_PIM_PACKETS) | |
174 | zlog_debug("%s: SPT bit is not set for (%s)", | |
175 | __PRETTY_FUNCTION__, child->sg_str); | |
176 | } | |
177 | } | |
178 | return size; | |
982bff89 DS |
179 | } |
180 | ||
d62a17ae | 181 | size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, |
182 | struct pim_jp_agg_group *sgs, size_t size) | |
79bdcd99 | 183 | { |
d62a17ae | 184 | struct listnode *node, *nnode; |
185 | struct pim_jp_sources *source; | |
186 | struct pim_upstream *up = NULL; | |
187 | struct in_addr stosend; | |
188 | uint8_t bits; | |
189 | uint8_t tgroups = 0; | |
190 | ||
191 | memset(grp, 0, size); | |
192 | pim_msg_addr_encode_ipv4_group((uint8_t *)&grp->g, sgs->group); | |
193 | ||
194 | for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source)) { | |
195 | /* number of joined/pruned sources */ | |
196 | if (source->is_join) | |
197 | grp->joins++; | |
198 | else | |
199 | grp->prunes++; | |
200 | ||
201 | if (source->up->sg.src.s_addr == INADDR_ANY) { | |
92b422f1 DS |
202 | struct pim_instance *pim = source->up->channel_oil->pim; |
203 | struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp); | |
d62a17ae | 204 | bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT |
205 | | PIM_ENCODE_RPT_BIT; | |
206 | stosend = rpf->rpf_addr.u.prefix4; | |
207 | /* Only Send SGRpt in case of *,G Join */ | |
208 | if (source->is_join) | |
209 | up = source->up; | |
210 | } else { | |
211 | bits = PIM_ENCODE_SPARSE_BIT; | |
212 | stosend = source->up->sg.src; | |
213 | } | |
214 | ||
215 | pim_msg_addr_encode_ipv4_source((uint8_t *)&grp->s[tgroups], | |
216 | stosend, bits); | |
217 | tgroups++; | |
218 | } | |
219 | ||
220 | if (up) { | |
221 | struct pim_upstream *child; | |
222 | ||
223 | for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child)) { | |
224 | if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE( | |
225 | child->flags)) { | |
226 | pim_msg_addr_encode_ipv4_source( | |
227 | (uint8_t *)&grp->s[tgroups], | |
228 | child->sg.src, | |
229 | PIM_ENCODE_SPARSE_BIT | |
230 | | PIM_ENCODE_RPT_BIT); | |
231 | tgroups++; | |
232 | PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE( | |
233 | child->flags); | |
234 | grp->prunes++; | |
235 | } | |
236 | } | |
237 | } | |
238 | ||
239 | grp->joins = htons(grp->joins); | |
240 | grp->prunes = htons(grp->prunes); | |
241 | ||
242 | return size; | |
346cffe3 | 243 | } |