3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 $QuaggaId: $Format:%an, %ai, %h$ $
35 #include "pim_iface.h"
36 #include "pim_zlookup.h"
37 #include "pim_ifchannel.h"
39 static struct in_addr
pim_rpf_find_rpf_addr(struct pim_upstream
*up
);
41 int pim_nexthop_lookup(struct pim_nexthop
*nexthop
,
42 struct in_addr addr
, struct interface
*incoming
)
44 struct pim_zlookup_nexthop nexthop_tab
[PIM_NEXTHOP_IFINDEX_TAB_SIZE
];
46 struct interface
*ifp
;
49 memset (nexthop_tab
, 0, sizeof (struct pim_zlookup_nexthop
) * PIM_NEXTHOP_IFINDEX_TAB_SIZE
);
53 num_ifindex
= zclient_lookup_nexthop(qpim_zclient_lookup
, nexthop_tab
,
54 PIM_NEXTHOP_IFINDEX_TAB_SIZE
,
55 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
56 if (num_ifindex
< 1) {
58 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
59 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
60 __FILE__
, __PRETTY_FUNCTION__
,
65 first_ifindex
= nexthop_tab
[0].ifindex
;
67 if (num_ifindex
> 1) {
69 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
70 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
71 __FILE__
, __PRETTY_FUNCTION__
,
72 num_ifindex
, addr_str
, first_ifindex
);
73 /* debug warning only, do not return */
76 ifp
= if_lookup_by_index(first_ifindex
);
79 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
80 zlog_warn("%s %s: could not find interface for ifindex %d (address %s)",
81 __FILE__
, __PRETTY_FUNCTION__
,
82 first_ifindex
, addr_str
);
89 first_ifindex
= ifp
->ifindex
;
94 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
95 zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
97 ifp
->name
, first_ifindex
, addr_str
);
98 /* debug warning only, do not return */
101 if (PIM_DEBUG_PIM_TRACE
) {
102 char nexthop_str
[100];
104 pim_inet4_dump("<nexthop?>", nexthop_tab
[0].nexthop_addr
, nexthop_str
, sizeof(nexthop_str
));
105 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
106 zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
107 __FILE__
, __PRETTY_FUNCTION__
,
108 nexthop_str
, addr_str
,
109 ifp
->name
, first_ifindex
,
110 nexthop_tab
[0].route_metric
,
111 nexthop_tab
[0].protocol_distance
);
114 /* update nextop data */
115 nexthop
->interface
= ifp
;
116 nexthop
->mrib_nexthop_addr
= nexthop_tab
[0].nexthop_addr
;
117 nexthop
->mrib_metric_preference
= nexthop_tab
[0].protocol_distance
;
118 nexthop
->mrib_route_metric
= nexthop_tab
[0].route_metric
;
123 static int nexthop_mismatch(const struct pim_nexthop
*nh1
,
124 const struct pim_nexthop
*nh2
)
126 return (nh1
->interface
!= nh2
->interface
)
128 (nh1
->mrib_nexthop_addr
.s_addr
!= nh2
->mrib_nexthop_addr
.s_addr
)
130 (nh1
->mrib_metric_preference
!= nh2
->mrib_metric_preference
)
132 (nh1
->mrib_route_metric
!= nh2
->mrib_route_metric
);
135 enum pim_rpf_result
pim_rpf_update(struct pim_upstream
*up
,
136 struct in_addr
*old_rpf_addr
,
137 struct interface
*incoming
)
139 struct in_addr save_rpf_addr
;
140 struct pim_nexthop save_nexthop
;
141 struct pim_rpf
*rpf
= &up
->rpf
;
143 save_nexthop
= rpf
->source_nexthop
; /* detect change in pim_nexthop */
144 save_rpf_addr
= rpf
->rpf_addr
; /* detect change in RPF'(S,G) */
146 if (pim_nexthop_lookup(&rpf
->source_nexthop
,
147 up
->upstream_addr
, incoming
)) {
148 return PIM_RPF_FAILURE
;
151 rpf
->rpf_addr
= pim_rpf_find_rpf_addr(up
);
152 if (PIM_INADDR_IS_ANY(rpf
->rpf_addr
) && PIM_DEBUG_PIM_EVENTS
) {
153 /* RPF'(S,G) not found */
156 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
157 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
158 zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream",
159 __FILE__
, __PRETTY_FUNCTION__
,
164 /* detect change in pim_nexthop */
165 if (nexthop_mismatch(&rpf
->source_nexthop
, &save_nexthop
)) {
167 if (PIM_DEBUG_PIM_EVENTS
) {
170 char nhaddr_str
[100];
171 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
172 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
173 pim_inet4_dump("<addr?>", rpf
->source_nexthop
.mrib_nexthop_addr
, nhaddr_str
, sizeof(nhaddr_str
));
174 zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d",
175 __FILE__
, __PRETTY_FUNCTION__
,
177 rpf
->source_nexthop
.interface
? rpf
->source_nexthop
.interface
->name
: "<ifname?>",
179 rpf
->source_nexthop
.mrib_metric_preference
,
180 rpf
->source_nexthop
.mrib_route_metric
);
183 pim_upstream_update_join_desired(up
);
184 pim_upstream_update_could_assert(up
);
185 pim_upstream_update_my_assert_metric(up
);
188 /* detect change in RPF_interface(S) */
189 if (save_nexthop
.interface
!= rpf
->source_nexthop
.interface
) {
191 if (PIM_DEBUG_PIM_EVENTS
) {
194 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
195 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
196 zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s",
197 __FILE__
, __PRETTY_FUNCTION__
,
199 save_nexthop
.interface
? save_nexthop
.interface
->name
: "<oldif?>",
200 rpf
->source_nexthop
.interface
? rpf
->source_nexthop
.interface
->name
: "<newif?>");
204 pim_upstream_rpf_interface_changed(up
, save_nexthop
.interface
);
207 /* detect change in RPF'(S,G) */
208 if (save_rpf_addr
.s_addr
!= rpf
->rpf_addr
.s_addr
) {
210 /* return old rpf to caller ? */
212 *old_rpf_addr
= save_rpf_addr
;
214 return PIM_RPF_CHANGED
;
221 RFC 4601: 4.1.6. State Summarization Macros
224 if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) {
225 return AssertWinner(S, G, RPF_interface(S) )
227 return NBR( RPF_interface(S), MRIB.next_hop( S ) )
231 RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data
232 packets should be coming and to which joins should be sent on the RP
233 tree and SPT, respectively.
235 static struct in_addr
pim_rpf_find_rpf_addr(struct pim_upstream
*up
)
237 struct pim_ifchannel
*rpf_ch
;
238 struct pim_neighbor
*neigh
;
239 struct in_addr rpf_addr
;
241 if (!up
->rpf
.source_nexthop
.interface
) {
244 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
245 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
246 zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)",
250 rpf_addr
.s_addr
= PIM_NET_INADDR_ANY
;
254 rpf_ch
= pim_ifchannel_find(up
->rpf
.source_nexthop
.interface
,
255 up
->source_addr
, up
->group_addr
);
257 if (rpf_ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
258 return rpf_ch
->ifassert_winner
;
262 /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */
264 neigh
= pim_if_find_neighbor(up
->rpf
.source_nexthop
.interface
,
265 up
->rpf
.source_nexthop
.mrib_nexthop_addr
);
267 rpf_addr
= neigh
->source_addr
;
269 rpf_addr
.s_addr
= PIM_NET_INADDR_ANY
;