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,
33 #include "pim_iface.h"
34 #include "pim_zlookup.h"
35 #include "pim_ifchannel.h"
37 static struct in_addr
pim_rpf_find_rpf_addr(struct pim_upstream
*up
);
39 int pim_nexthop_lookup(struct pim_nexthop
*nexthop
,
40 struct in_addr addr
, struct interface
*incoming
)
42 struct pim_zlookup_nexthop nexthop_tab
[PIM_NEXTHOP_IFINDEX_TAB_SIZE
];
44 struct interface
*ifp
;
47 memset (nexthop_tab
, 0, sizeof (struct pim_zlookup_nexthop
) * PIM_NEXTHOP_IFINDEX_TAB_SIZE
);
51 num_ifindex
= zclient_lookup_nexthop(qpim_zclient_lookup
, nexthop_tab
,
52 PIM_NEXTHOP_IFINDEX_TAB_SIZE
,
53 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
54 if (num_ifindex
< 1) {
56 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
57 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
58 __FILE__
, __PRETTY_FUNCTION__
,
63 first_ifindex
= nexthop_tab
[0].ifindex
;
65 if (num_ifindex
> 1) {
67 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
68 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
69 __FILE__
, __PRETTY_FUNCTION__
,
70 num_ifindex
, addr_str
, first_ifindex
);
71 /* debug warning only, do not return */
74 ifp
= if_lookup_by_index(first_ifindex
);
77 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
78 zlog_warn("%s %s: could not find interface for ifindex %d (address %s)",
79 __FILE__
, __PRETTY_FUNCTION__
,
80 first_ifindex
, addr_str
);
87 first_ifindex
= ifp
->ifindex
;
92 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
93 zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
95 ifp
->name
, first_ifindex
, addr_str
);
96 /* debug warning only, do not return */
99 if (PIM_DEBUG_PIM_TRACE
) {
100 char nexthop_str
[100];
102 pim_inet4_dump("<nexthop?>", nexthop_tab
[0].nexthop_addr
, nexthop_str
, sizeof(nexthop_str
));
103 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
104 zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
105 __FILE__
, __PRETTY_FUNCTION__
,
106 nexthop_str
, addr_str
,
107 ifp
->name
, first_ifindex
,
108 nexthop_tab
[0].route_metric
,
109 nexthop_tab
[0].protocol_distance
);
112 /* update nextop data */
113 nexthop
->interface
= ifp
;
114 nexthop
->mrib_nexthop_addr
= nexthop_tab
[0].nexthop_addr
;
115 nexthop
->mrib_metric_preference
= nexthop_tab
[0].protocol_distance
;
116 nexthop
->mrib_route_metric
= nexthop_tab
[0].route_metric
;
121 static int nexthop_mismatch(const struct pim_nexthop
*nh1
,
122 const struct pim_nexthop
*nh2
)
124 return (nh1
->interface
!= nh2
->interface
)
126 (nh1
->mrib_nexthop_addr
.s_addr
!= nh2
->mrib_nexthop_addr
.s_addr
)
128 (nh1
->mrib_metric_preference
!= nh2
->mrib_metric_preference
)
130 (nh1
->mrib_route_metric
!= nh2
->mrib_route_metric
);
133 enum pim_rpf_result
pim_rpf_update(struct pim_upstream
*up
,
134 struct in_addr
*old_rpf_addr
,
135 struct interface
*incoming
)
137 struct in_addr save_rpf_addr
;
138 struct pim_nexthop save_nexthop
;
139 struct pim_rpf
*rpf
= &up
->rpf
;
141 save_nexthop
= rpf
->source_nexthop
; /* detect change in pim_nexthop */
142 save_rpf_addr
= rpf
->rpf_addr
; /* detect change in RPF'(S,G) */
144 if (pim_nexthop_lookup(&rpf
->source_nexthop
,
145 up
->upstream_addr
, incoming
)) {
146 return PIM_RPF_FAILURE
;
149 rpf
->rpf_addr
= pim_rpf_find_rpf_addr(up
);
150 if (PIM_INADDR_IS_ANY(rpf
->rpf_addr
) && PIM_DEBUG_PIM_EVENTS
) {
151 /* RPF'(S,G) not found */
154 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
155 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
156 zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream",
157 __FILE__
, __PRETTY_FUNCTION__
,
162 /* detect change in pim_nexthop */
163 if (nexthop_mismatch(&rpf
->source_nexthop
, &save_nexthop
)) {
165 if (PIM_DEBUG_PIM_EVENTS
) {
168 char nhaddr_str
[100];
169 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
170 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
171 pim_inet4_dump("<addr?>", rpf
->source_nexthop
.mrib_nexthop_addr
, nhaddr_str
, sizeof(nhaddr_str
));
172 zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d",
173 __FILE__
, __PRETTY_FUNCTION__
,
175 rpf
->source_nexthop
.interface
? rpf
->source_nexthop
.interface
->name
: "<ifname?>",
177 rpf
->source_nexthop
.mrib_metric_preference
,
178 rpf
->source_nexthop
.mrib_route_metric
);
181 pim_upstream_update_join_desired(up
);
182 pim_upstream_update_could_assert(up
);
183 pim_upstream_update_my_assert_metric(up
);
186 /* detect change in RPF_interface(S) */
187 if (save_nexthop
.interface
!= rpf
->source_nexthop
.interface
) {
189 if (PIM_DEBUG_PIM_EVENTS
) {
192 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
193 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
194 zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s",
195 __FILE__
, __PRETTY_FUNCTION__
,
197 save_nexthop
.interface
? save_nexthop
.interface
->name
: "<oldif?>",
198 rpf
->source_nexthop
.interface
? rpf
->source_nexthop
.interface
->name
: "<newif?>");
202 pim_upstream_rpf_interface_changed(up
, save_nexthop
.interface
);
205 /* detect change in RPF'(S,G) */
206 if (save_rpf_addr
.s_addr
!= rpf
->rpf_addr
.s_addr
) {
208 /* return old rpf to caller ? */
210 *old_rpf_addr
= save_rpf_addr
;
212 return PIM_RPF_CHANGED
;
219 RFC 4601: 4.1.6. State Summarization Macros
222 if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) {
223 return AssertWinner(S, G, RPF_interface(S) )
225 return NBR( RPF_interface(S), MRIB.next_hop( S ) )
229 RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data
230 packets should be coming and to which joins should be sent on the RP
231 tree and SPT, respectively.
233 static struct in_addr
pim_rpf_find_rpf_addr(struct pim_upstream
*up
)
235 struct pim_ifchannel
*rpf_ch
;
236 struct pim_neighbor
*neigh
;
237 struct in_addr rpf_addr
;
239 if (!up
->rpf
.source_nexthop
.interface
) {
242 pim_inet4_dump("<src?>", up
->source_addr
, src_str
, sizeof(src_str
));
243 pim_inet4_dump("<grp?>", up
->group_addr
, grp_str
, sizeof(grp_str
));
244 zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)",
248 rpf_addr
.s_addr
= PIM_NET_INADDR_ANY
;
252 rpf_ch
= pim_ifchannel_find(up
->rpf
.source_nexthop
.interface
,
253 up
->source_addr
, up
->group_addr
);
255 if (rpf_ch
->ifassert_state
== PIM_IFASSERT_I_AM_LOSER
) {
256 return rpf_ch
->ifassert_winner
;
260 /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */
262 neigh
= pim_if_find_neighbor(up
->rpf
.source_nexthop
.interface
,
263 up
->rpf
.source_nexthop
.mrib_nexthop_addr
);
265 rpf_addr
= neigh
->source_addr
;
267 rpf_addr
.s_addr
= PIM_NET_INADDR_ANY
;