]>
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", | |
126 | __PRETTY_FUNCTION__, up->sg_str); | |
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", | |
147 | __PRETTY_FUNCTION__, | |
148 | up->sg_str, | |
149 | child->sg_str); | |
150 | } else if (PIM_DEBUG_PIM_PACKETS) | |
151 | zlog_debug( | |
152 | "%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", | |
153 | __PRETTY_FUNCTION__, up->sg_str, | |
154 | child->sg_str); | |
0688d603 AK |
155 | } else if (pim_upstream_empty_inherited_olist(child)) { |
156 | /* S is supposed to be forwarded along the RPT | |
157 | * but it's inherited OIL is empty. So just | |
158 | * prune it off. | |
159 | */ | |
160 | size += sizeof( | |
d62a17ae | 161 | struct pim_encoded_source_ipv4); |
0688d603 | 162 | PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( |
d62a17ae | 163 | child->flags); |
0688d603 AK |
164 | if (PIM_DEBUG_PIM_PACKETS) |
165 | zlog_debug( | |
d62a17ae | 166 | "%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", |
167 | __PRETTY_FUNCTION__, | |
168 | child->sg_str); | |
d62a17ae | 169 | } else if (PIM_DEBUG_PIM_PACKETS) |
0688d603 AK |
170 | zlog_debug( |
171 | "%s: Do not add Prune %s to compound message %s", | |
172 | __PRETTY_FUNCTION__, child->sg_str, | |
173 | up->sg_str); | |
d62a17ae | 174 | } |
175 | } | |
176 | return size; | |
982bff89 DS |
177 | } |
178 | ||
d62a17ae | 179 | size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, |
180 | struct pim_jp_agg_group *sgs, size_t size) | |
79bdcd99 | 181 | { |
d62a17ae | 182 | struct listnode *node, *nnode; |
183 | struct pim_jp_sources *source; | |
184 | struct pim_upstream *up = NULL; | |
185 | struct in_addr stosend; | |
186 | uint8_t bits; | |
187 | uint8_t tgroups = 0; | |
188 | ||
189 | memset(grp, 0, size); | |
190 | pim_msg_addr_encode_ipv4_group((uint8_t *)&grp->g, sgs->group); | |
191 | ||
192 | for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source)) { | |
193 | /* number of joined/pruned sources */ | |
194 | if (source->is_join) | |
195 | grp->joins++; | |
196 | else | |
197 | grp->prunes++; | |
198 | ||
199 | if (source->up->sg.src.s_addr == INADDR_ANY) { | |
92b422f1 DS |
200 | struct pim_instance *pim = source->up->channel_oil->pim; |
201 | struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp); | |
d62a17ae | 202 | bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT |
203 | | PIM_ENCODE_RPT_BIT; | |
204 | stosend = rpf->rpf_addr.u.prefix4; | |
205 | /* Only Send SGRpt in case of *,G Join */ | |
206 | if (source->is_join) | |
207 | up = source->up; | |
208 | } else { | |
209 | bits = PIM_ENCODE_SPARSE_BIT; | |
210 | stosend = source->up->sg.src; | |
211 | } | |
212 | ||
213 | pim_msg_addr_encode_ipv4_source((uint8_t *)&grp->s[tgroups], | |
214 | stosend, bits); | |
215 | tgroups++; | |
216 | } | |
217 | ||
218 | if (up) { | |
219 | struct pim_upstream *child; | |
220 | ||
221 | for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child)) { | |
222 | if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE( | |
223 | child->flags)) { | |
224 | pim_msg_addr_encode_ipv4_source( | |
225 | (uint8_t *)&grp->s[tgroups], | |
226 | child->sg.src, | |
227 | PIM_ENCODE_SPARSE_BIT | |
228 | | PIM_ENCODE_RPT_BIT); | |
229 | tgroups++; | |
230 | PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE( | |
231 | child->flags); | |
232 | grp->prunes++; | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | grp->joins = htons(grp->joins); | |
238 | grp->prunes = htons(grp->prunes); | |
239 | ||
240 | return size; | |
346cffe3 | 241 | } |