]>
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, |
d57a8bbf | 42 | uint8_t pim_msg_type, bool no_fwd) |
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; | |
d57a8bbf | 51 | header->Nbit = no_fwd; |
d62a17ae | 52 | header->reserved = 0; |
53 | ||
54 | ||
55 | header->checksum = 0; | |
56 | /* | |
57 | * The checksum for Registers is done only on the first 8 bytes of the | |
58 | * packet, | |
59 | * including the PIM header and the next 4 bytes, excluding the data | |
60 | * packet portion | |
61 | */ | |
62 | if (pim_msg_type == PIM_MSG_TYPE_REGISTER) | |
63 | header->checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN); | |
64 | else | |
65 | header->checksum = in_cksum(pim_msg, pim_msg_size); | |
12e41d03 DL |
66 | } |
67 | ||
f8e7d799 | 68 | uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr) |
12e41d03 | 69 | { |
d62a17ae | 70 | buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ |
71 | buf[1] = '\0'; /* native encoding */ | |
72 | memcpy(buf + 2, &addr, sizeof(struct in_addr)); | |
12e41d03 | 73 | |
d62a17ae | 74 | return buf + PIM_ENCODED_IPV4_UCAST_SIZE; |
12e41d03 DL |
75 | } |
76 | ||
f8e7d799 | 77 | uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr) |
12e41d03 | 78 | { |
d62a17ae | 79 | buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ |
80 | buf[1] = '\0'; /* native encoding */ | |
81 | buf[2] = '\0'; /* reserved */ | |
82 | buf[3] = 32; /* mask len */ | |
83 | memcpy(buf + 4, &addr, sizeof(struct in_addr)); | |
12e41d03 | 84 | |
d62a17ae | 85 | return buf + PIM_ENCODED_IPV4_GROUP_SIZE; |
12e41d03 DL |
86 | } |
87 | ||
d62a17ae | 88 | uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr, |
89 | uint8_t bits) | |
12e41d03 | 90 | { |
d62a17ae | 91 | buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ |
92 | buf[1] = '\0'; /* native encoding */ | |
93 | buf[2] = bits; | |
94 | buf[3] = 32; /* mask len */ | |
95 | memcpy(buf + 4, &addr, sizeof(struct in_addr)); | |
12e41d03 | 96 | |
d62a17ae | 97 | return buf + PIM_ENCODED_IPV4_SOURCE_SIZE; |
12e41d03 | 98 | } |
346cffe3 | 99 | |
982bff89 DS |
100 | /* |
101 | * For the given 'struct pim_jp_sources' list | |
102 | * determine the size_t it would take up. | |
103 | */ | |
d62a17ae | 104 | size_t pim_msg_get_jp_group_size(struct list *sources) |
982bff89 | 105 | { |
d62a17ae | 106 | struct pim_jp_sources *js; |
107 | size_t size = 0; | |
108 | ||
9403d285 DS |
109 | if (!sources) |
110 | return 0; | |
111 | ||
d62a17ae | 112 | size += sizeof(struct pim_encoded_group_ipv4); |
113 | size += 4; // Joined sources (2) + Pruned Sources (2) | |
114 | ||
115 | size += sizeof(struct pim_encoded_source_ipv4) * sources->count; | |
116 | ||
117 | js = listgetdata(listhead(sources)); | |
be523269 | 118 | if (js && js->up->sg.src.s_addr == INADDR_ANY && js->is_join) { |
d62a17ae | 119 | struct pim_upstream *child, *up; |
120 | struct listnode *up_node; | |
121 | ||
122 | up = js->up; | |
123 | if (PIM_DEBUG_PIM_PACKETS) | |
124 | zlog_debug( | |
125 | "%s: Considering (%s) children for (S,G,rpt) prune", | |
5e81f5dd | 126 | __func__, up->sg_str); |
d62a17ae | 127 | |
128 | for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) { | |
0688d603 AK |
129 | if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) { |
130 | /* If we are using SPT and the SPT and RPT IIFs | |
131 | * are different we can prune the source off | |
132 | * of the RPT. | |
133 | * If RPF_interface(S) is not resolved hold | |
134 | * decision to prune as SPT may end up on the | |
135 | * same IIF as RPF_interface(RP). | |
136 | */ | |
137 | if (child->rpf.source_nexthop.interface && | |
138 | !pim_rpf_is_same(&up->rpf, | |
139 | &child->rpf)) { | |
d62a17ae | 140 | size += sizeof( |
141 | struct pim_encoded_source_ipv4); | |
142 | PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( | |
143 | child->flags); | |
144 | if (PIM_DEBUG_PIM_PACKETS) | |
145 | zlog_debug( | |
146 | "%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message", | |
5e81f5dd | 147 | __func__, up->sg_str, |
d62a17ae | 148 | child->sg_str); |
149 | } else if (PIM_DEBUG_PIM_PACKETS) | |
150 | zlog_debug( | |
151 | "%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", | |
5e81f5dd | 152 | __func__, up->sg_str, |
d62a17ae | 153 | child->sg_str); |
0688d603 AK |
154 | } else if (pim_upstream_empty_inherited_olist(child)) { |
155 | /* S is supposed to be forwarded along the RPT | |
156 | * but it's inherited OIL is empty. So just | |
157 | * prune it off. | |
158 | */ | |
159 | size += sizeof( | |
d62a17ae | 160 | struct pim_encoded_source_ipv4); |
0688d603 | 161 | PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( |
d62a17ae | 162 | child->flags); |
0688d603 AK |
163 | if (PIM_DEBUG_PIM_PACKETS) |
164 | zlog_debug( | |
5e81f5dd DS |
165 | "%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", |
166 | __func__, child->sg_str); | |
d62a17ae | 167 | } else if (PIM_DEBUG_PIM_PACKETS) |
0688d603 | 168 | zlog_debug( |
5e81f5dd DS |
169 | "%s: Do not add Prune %s to compound message %s", |
170 | __func__, child->sg_str, up->sg_str); | |
d62a17ae | 171 | } |
172 | } | |
173 | return size; | |
982bff89 DS |
174 | } |
175 | ||
d62a17ae | 176 | size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, |
177 | struct pim_jp_agg_group *sgs, size_t size) | |
79bdcd99 | 178 | { |
d62a17ae | 179 | struct listnode *node, *nnode; |
180 | struct pim_jp_sources *source; | |
181 | struct pim_upstream *up = NULL; | |
182 | struct in_addr stosend; | |
183 | uint8_t bits; | |
184 | uint8_t tgroups = 0; | |
185 | ||
186 | memset(grp, 0, size); | |
187 | pim_msg_addr_encode_ipv4_group((uint8_t *)&grp->g, sgs->group); | |
188 | ||
189 | for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source)) { | |
190 | /* number of joined/pruned sources */ | |
191 | if (source->is_join) | |
192 | grp->joins++; | |
193 | else | |
194 | grp->prunes++; | |
195 | ||
196 | if (source->up->sg.src.s_addr == INADDR_ANY) { | |
92b422f1 DS |
197 | struct pim_instance *pim = source->up->channel_oil->pim; |
198 | struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp); | |
d62a17ae | 199 | bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT |
200 | | PIM_ENCODE_RPT_BIT; | |
201 | stosend = rpf->rpf_addr.u.prefix4; | |
202 | /* Only Send SGRpt in case of *,G Join */ | |
203 | if (source->is_join) | |
204 | up = source->up; | |
205 | } else { | |
206 | bits = PIM_ENCODE_SPARSE_BIT; | |
207 | stosend = source->up->sg.src; | |
208 | } | |
209 | ||
210 | pim_msg_addr_encode_ipv4_source((uint8_t *)&grp->s[tgroups], | |
211 | stosend, bits); | |
212 | tgroups++; | |
213 | } | |
214 | ||
215 | if (up) { | |
216 | struct pim_upstream *child; | |
217 | ||
218 | for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child)) { | |
219 | if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE( | |
220 | child->flags)) { | |
221 | pim_msg_addr_encode_ipv4_source( | |
222 | (uint8_t *)&grp->s[tgroups], | |
223 | child->sg.src, | |
224 | PIM_ENCODE_SPARSE_BIT | |
225 | | PIM_ENCODE_RPT_BIT); | |
226 | tgroups++; | |
227 | PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE( | |
228 | child->flags); | |
229 | grp->prunes++; | |
230 | } | |
231 | } | |
232 | } | |
233 | ||
234 | grp->joins = htons(grp->joins); | |
235 | grp->prunes = htons(grp->prunes); | |
236 | ||
237 | return size; | |
346cffe3 | 238 | } |