summaryrefslogtreecommitdiffstats
path: root/bgpd
Commit message (Collapse)AuthorAgeFilesLines
...
| * lib: add sockopt helper for setting IPV6_V6ONLY and use itDavid Lamparter2011-12-131-8/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | getaddrinfo returns a list of socket parameters for listening. it will contain both IPv4 and IPv6 listening sockets. unless we use IPV6_V6ONLY on the IPv6 ones, only the socket listed first will work. if the IPv4 one came first, the IPv6 one would get an "Address in use" error. this functionality was already present for bgpd and its listening sockets. as it is needed for vtys as well, make it a common helper. Conflicts: lib/sockunion.c
| * lib: put route_types.txt to real useDavid Lamparter2011-12-131-193/+76
| | | | | | | | | | | | | | | | | | | | | | this replaces most occurences of routing protocol lists by preprocessor defines from route_types.h. the latter is autogenerated from route_types.txt by a perl script (previously awk). adding a routing protocol now is mostly a matter of changing route_types.txt and log.c. Conflicts: lib/route_types.awk
| * build: delete .cvsignore filesDenis Ovsienko2011-12-131-15/+0
| |
| * quagga: option "-z" ("--socket <path>") addedVyacheslav Trushkin2011-12-132-7/+7
| | | | | | | | | | | | | | | | | | | | | | All daemons modified to support custom path to zserv socket. lib: generalize a zclient connection zclient_socket_connect added. zclient_socket and zclient_socket_un were hidden under static expression. "zclient_serv_path_set" modified.
| * bgpd: implement 'match probability' in route-mapsVyacheslav Trushkin2011-12-131-1/+105
| | | | | | | | | | New clause 'match probability <percentage value>' was added in route-maps (bgpd/bgp_routemap.c modified).
| * bgp: use VTY_GET_INTEGER_RANGE() in bgp_clear()Ulrich Weber2011-12-131-9/+1
| | | | | | | | | | | | Second patch replaces "VTY_GET_LONG ("AS", as_ul, arg);" by "VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX);" as done in all other code, which parses AS numbers.
| * bgpd: cleanup privs on terminationStephen Hemminger2011-12-071-0/+1
| | | | | | | | | | When doing valgrind testing, the privledges from zprivs_init() need to be cleaned up on exit.
| * bgpd: store nexthop info for redistributed IPV6 routesStephen Hemminger2011-12-063-12/+31
| | | | | | | | | | | | | | BGP was ignoring nexthop info for static and other redistributed routes for IPv6. Build extra attribute info to store the nexthop. See also: https://bugzilla.vyatta.com/show_bug.cgi?id=6073
| * bgpd: fix memory leak for extra attributesOleg A. Arkhangelsky2011-12-031-0/+1
| | | | | | | | this fixes commit b881c7074bb698aeb1b099175b325734fc6e44d2
| * bgpd: remove unused function bgp_bind_addressDavid Lamparter2011-11-211-26/+0
| | | | | | | | bgp_bind_address is replaced with sockunion_bind.
| * bgpd: fix update-source for IPv6 (BZ#548)David Lamparter2011-11-211-12/+27
| | | | | | | | | | | | | | | | if update-source was given as interface name, bgpd was unconditionally trying to bind to an IPv4 address from that interface. change function to find the best-matching (number of address bits) same-family address on the interface.
| * bgpd: fix "nexthop-local unchanged" (BZ#350)Dylan Hall2011-11-151-0/+5
| |
| * bgpd: justify capabilities for TOS settingChris Luke2011-11-152-5/+10
| | | | | | | | | | | | | | | | | | | | | | To set the TOS bits on TCP connections, platforms that restrict capabilities need the priv level to be raised before the sockopt is set, and this requires the ZCAP_NET_ADMIN priv. * bgp_main.c: update _caps_p to include ZCAP_NET_ADMIN * bgp_network.c * bgp_connect(): request ZPRIVS_RAISE/ZPRIVS_LOWER * bgp_listener(): request ZPRIVS_RAISE earlier
| * bgpd: revised fix to --dryrun (BZ#622)Sergey Y. Afonin2011-11-151-3/+4
| |
| * bgpd: fix 2 more cases of length error reportingDenis Ovsienko2011-10-261-2/+2
| | | | | | | | | | * bgp_attr.c (bgp_attr_originator_id, bgp_attr_cluster_list): provide required arguments to bgp_attr_malformed()
| * bgpd: check AGGREGATOR attr flags (BZ#678)Denis Ovsienko2011-10-221-0/+17
| | | | | | | | | | * bgp_attr.c * bgp_attr_aggregator(): check Optional/Transitive flag bits
| * bgpd: fix more regressions in attr flag checksDenis Ovsienko2011-10-191-4/+4
| | | | | | | | | | | | | | | | | | | | | | Commit 05a4936b713b9882171d0f7fb20b8439df23939e fixed some of the attributes involved, but not all. This commit should do it. * bgp_attr.c * bgp_attr_originator_id() * bgp_attr_cluster_list() * bgp_mp_reach_parse() * bgp_mp_unreach_parse()
| * bgpd: use bgp_attr_malformed()Denis Ovsienko2011-10-181-17/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Some of the recent attribute flags/length checks copied from QRE use bgp_notify_send_with_data() directly, but master branch assumes using bgp_attr_malformed(). * bgp_attr.c * bgp_attr_med() * bgp_attr_local_pref() * bgp_attr_atomic() * bgp_attr_originator_id() * bgp_attr_cluster_list() * bgp_mp_reach_parse() * bgp_mp_unreach_parse()
| * bgpd: add flag checks for MP_(UN)REACH_NLRIDenis Ovsienko2011-10-172-9/+40
| | | | | | | | | | | | | | | | | | | | * bgp_attr.[ch] * bgp_mp_reach_parse(): add extra arguments and a uniform flag check block * bgp_mp_unreach_parse(): idem * bgp_attr_parse(): provide extra arguments * bgp_mp_attr_test.c * parse_test(): justify respective calls
| * bgpd: fix spelling of CLUSTER_LISTDenis Ovsienko2011-10-171-1/+1
| |
| * bgpd: check CLUSTER_LIST attribute flagsDenis Ovsienko2011-10-171-2/+17
| | | | | | | | | | | | | | | | * bgp_attr.c * bgp_attr_cluster_list(): accept extra argument, add checks for "optional", "transitive" and "partial" bits, log each error condition independently * bgp_attr_parse(): provide extra arguments
| * bgpd: check ORIGINATOR_ID attribute flagsDenis Ovsienko2011-10-171-2/+18
| | | | | | | | | | | | | | | | * bgp_attr.c * bgp_attr_originator_id(): accept extra argument, add checks for "optional", "transitive" and "partial" bits, log each error condition independently * bgp_attr_parse(): provide extra arguments
| * IPv6 transport class suppportStephen Hemminger2011-10-171-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | IPv6 supports the same concept of differentiated service for routing protocols as IPv4, but like too many things, the standards committee decided that having two names for the same thing wasn't good enough and introduced a third more generic term transport class. The socket option to set transport class works the same as IPv4, but the arguments are different. * lib/sockopt.[ch] * setsockopt_ipv6_tclass(): new function * bgpd/bgp_network.c * bgp_connect(): set socket option * bgp_listener(): set socket option * ospf6d/ospf6_network.c * ospf6_set_transport_class(): new function * ospf6_serv_sock(): set socket option * ripngd/ripngd.c * ripng_make_socket(): set socket option
| * bgpd: fix regression in improved attr flag checksDenis Ovsienko2011-10-121-5/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | Commit 2febf323411c1aed9d7694898f852ce2ef36a7e5 assumed every flag bit except optional/transitive/partial unset, which at times could not be true for "extended length" bit. * bgp_attr.c * bgp_attr_origin(): exclude BGP_ATTR_FLAG_EXTLEN from comparison * bgp_attr_nexthop(): idem * bgp_attr_med(): idem * bgp_attr_local_pref(): idem * bgp_attr_atomic(): idem
| * bgpd: fix parsing of graceful restart cap. (#663)Peter Pentchev2011-10-081-1/+1
| | | | | | | | | | | | | | | | | | | | "While setting up a testbed, I ran across a little problem in the parsing of the "graceful restart" BGP capability that resulted in Quagga not actually activating it for the peer in question - when the peer sent a single AFI/SAFI block." * bgp_open.c * bgp_capability_restart(): actually process the last AFI/SAFI block
| * bgpd: improve attr length error handling (BZ#679)Denis Ovsienko2011-10-081-12/+19
| | | | | | | | | | | | | | | | | | | | | | | | * bgp_attr.c * bgp_attr_parse(): provide extra argument to bgp_attr_aggregator() * bgp_attr_local_pref(): use bgp_notify_send_with_data() * bgp_attr_atomic(): idem * bgp_attr_aggregator(): idem Conflicts: bgpd/bgp_attr.c
| * bgpd: improve attr flags checksDenis Ovsienko2011-09-301-138/+53
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Do not check each of the Optional/Transitive/Partial attribute flag bits, when their only valid combination is known in advance, but still perform bit-deep error message logging. This change assumes unused (low-order) 4 bits of the flag octet cleared. * bgp_attr.c * bgp_attr_origin(): rewrite check * bgp_attr_nexthop(): idem * bgp_attr_med(): idem * bgp_attr_local_pref(): idem * bgp_attr_atomic(): idem Conflicts: bgpd/bgp_attr.c
| * bgpd: ignore 4 bits of attribute flags byteDenis Ovsienko2011-09-301-1/+4
| |
| * bgpd: add missing "partial" flag checks (BZ#676)Denis Ovsienko2011-09-301-3/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ORIGIN handling function used to have "partial" bit check and recent commits added it for NEXT_HOP, MULTI_EXIT_DISC and ATOMIC_AGGREGATE cases. This commit adds "partial" check for AS_PATH and LOCAL_PREF cases, which should leave attributes 1 through 6 inclusive completely covered with attribute flags checks. * bgp_attr.c * bgp_attr_origin(): use bit-by-bit checks for better diagnostics * bgp_attr_aspath(): add flag check * bgp_attr_local_pref(): idem Conflicts: bgpd/bgp_attr.c
| * bgpd: improve NEXT_HOP attribute checks (BZ#680)Denis Ovsienko2011-09-301-6/+39
| | | | | | | | | | | | | | | | | | | | | | | | * lib/prefix.h * IPV4_CLASS_DE(): new helper macro * bgp_attr.c * bgp_attr_nexthop(): add check for "partial" bit, refresh flag error reporting, explain meaning of RFC4271 section 6.3 and implement it Conflicts: bgpd/bgp_attr.c
| * bgpd: rename SAFI 3 according to RFC4760Denis Ovsienko2011-09-293-8/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | - SAFI value 3 is reserved. It was assigned by RFC 2858 for a use that was never fully implemented, so it is deprecated by this document. * zebra.h: rename macro * bgp_fsm.c: (bgp_graceful_restart_timer_expire, bgp_graceful_stale_timer_expire, bgp_stop, bgp_establish): update * bgpd.c: (peer_nsf_stop): update * bgp_open.c: (bgp_capability_vty_out): SAFI 3 isn't a recognized case any more
| * bgpd: more SAFI fixesDenis Ovsienko2011-09-295-41/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (with resolved conflict in bgpd/bgp_packet.c) Two macros resolving to the same integer constant broke a case block and a more thorough merge of BGP_SAFI_VPNV4 and BGP_SAFI_VPNV6 was performed. * bgpd.h: MPLS-labeled VPN SAFI is AFI-independent, switch to single * macro * bgp_capability_test.c: update test data * bgp_mp_attr_test.c: idem * bgp_route.c: (bgp_maximum_prefix_overflow, bgp_table_stats_vty) update macro and check conditions (where appropriate) * bgp_packet.c: (bgp_route_refresh_send, bgp_capability_send, bgp_update_receive, bgp_route_refresh_receive): idem * bgp_open.c: (bgp_capability_vty_out, bgp_afi_safi_valid_indices, bgp_open_capability_orf, bgp_open_capability): idem * bgp_attr.c: (bgp_mp_reach_parse, bgp_packet_attribute, bgp_packet_withdraw): idem
| * bgpd: fix SAFI for for MPLS labeled VPN-IPv6Denis Ovsienko2011-09-292-2/+2
| | | | | | | | | | * bgpd.h: change value of BGP_SAFI_VPNV6 to 128 (RFC4659, BZ#659) * bgp_route.c: (bgp_table_stats_vty) fix length argument to strncmp()
| * bgpd: don't be confused by "unspecific" subcode in the NOTIFY message.Dmitrij Tejblum2011-09-272-1/+7
| | | | | | | | | | | | * bgp_debug.c (bgp_notify_open_msg, bgp_notify_update_msg, bgp_notify_cease_msg, bgp_notify_capability_msg): add messages for "unspecific" subcode.
| * bgpd: spellingDenis Ovsienko2011-09-271-1/+1
| |
| * bgpd: spellingDenis Ovsienko2011-09-271-1/+1
| |
| * bgpd: check ATOMIC_AGGREGATE attr flags (BZ#678)Denis Ovsienko2011-09-271-2/+38
| | | | | | | | | | | | | | | | * bgp_attr.c * bgp_attr_atomic(): accept extra argument, add checks for "optional", "transitive" and "partial" bits, log each error condition independently * bgp_attr_parse(): provide extra argument
| * bgpd: check MULTI_EXIT_DISC attr flags (BZ#677)Denis Ovsienko2011-09-271-0/+32
| | | | | | | | | | | | * bgp_attr.c * bgp_attr_med(): add checks for "optional", "transitive" and "partial" bits, log each error condition independently
| * bgpd: check LOCAL_PREF attribute flags (BZ#674)Denis Ovsienko2011-09-271-2/+27
| | | | | | | | | | | | | | | | * bgp_attr.c * bgp_attr_local_pref(): accept extra argument, add checks for "optional" and "transitive" bits, log each error condition independently * bgp_attr_parse(): provide extra argument
| * bgpd: add useful notification logs (BZ#616)heasley2011-09-271-3/+16
| | | | | | | | | | * bgp_packet.c * bgp_notify_send_with_data(): add calls to zlog_info()
| * bgpd: consistent log msg format (BZ#565)heasley2011-09-271-5/+5
| |
| * bgpd: CVE-2011-3327 (ext. comm. buffer overflow)CROSS2011-09-261-7/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | This vulnerability (CERT-FI #513254) was reported by CROSS project. They have also suggested a fix to the problem, which was found acceptable. The problem occurs when bgpd receives an UPDATE message containing 255 unknown AS_PATH attributes in Path Attribute Extended Communities. This causes a buffer overlow in bgpd. * bgp_ecommunity.c * ecommunity_ecom2str(): perform size check earlier
| * Merge branch 'attr-errors'Paul Jakma2011-07-2913-439/+577
| |\ | | | | | | | | | | | | | | | | | | | | | Contains BGP fixes: - set extcommunity crash: tihs patch tries to make the refcounting more robust but does not fully solve the problem, sadly. - BGP attribute error handling: Little testing.
| | * bgpd: Implement revised error handling for partial optional/trans. attributesPaul Jakma2011-03-214-233/+378
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * BGP error handling generally boils down to "reset session". This was fine when all BGP speakers pretty much understood all BGP messages. However the increasing deployment of new attribute types has shown this approach to cause problems, in particular where a new attribute type is "tunneled" over some speakers which do not understand it, and then arrives at a speaker which does but considers it malformed (e.g. corruption along the way, or because of early implementation bugs/interop issues). To mitigate this drafts before the IDR (likely to be adopted) propose to treat errors in partial (i.e. not understood by neighbour), optional transitive attributes, when received from eBGP peers, as withdrawing only the NLRIs in the affected UPDATE, rather than causing the entire session to be reset. See: http://tools.ietf.org/html/draft-scudder-idr-optional-transitive * bgp_aspath.c: (assegments_parse) Replace the "NULL means valid, 0-length OR an error" return value with an error code - instead taking pointer to result structure as arg. (aspath_parse) adjust to suit previous change, but here NULL really does mean error in the external interface. * bgp_attr.h (bgp_attr_parse) use an explictly typed and enumerated value to indicate return result. (bgp_attr_unintern_sub) cleans up just the members of an attr, but not the attr itself, for benefit of those who use a stack-local attr. * bgp_attr.c: (bgp_attr_unintern_sub) split out from bgp_attr_unintern (bgp_attr_unintern) as previous. (bgp_attr_malformed) helper function to centralise decisions on how to handle errors in attributes. (bgp_attr_{aspathlimit,origin,etc..}) Use bgp_attr_malformed. (bgp_attr_aspathlimit) Subcode for error specifc to this attr should be BGP_NOTIFY_UPDATE_OPT_ATTR_ERR. (bgp_attr_as4_path) be more rigorous about checks, ala bgp_attr_as_path. (bgp_attr_parse) Adjust to deal with the additional error level that bgp_attr_ parsers can raise, and also similarly return appropriate error back up to (bgp_update_receive). Try to avoid leaking as4_path. * bgp_packet.c: (bgp_update_receive) Adjust to deal with BGP_ATTR_PARSE_WITHDRAW error level from bgp_attr_parse, which should lead to a withdraw, by making the attribute parameter in call to (bgp_nlri_parse) conditional on the error, so the update case morphs also into a withdraw. Use bgp_attr_unintern_sub from above, instead of doing this itself. Fix error case returns which were not calling bgp_attr_unintern_sub and probably leaking memory. * tests/aspath_test.c: Fix to work for null return with bad segments
| | * bgpd: Try fix extcommunity resource allocation probs, particularly with 'set ↵Paul Jakma2011-03-2113-109/+126
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | extcom..' * Extended communities has some kind of resource allocation problem which causes a double-free if the 'set extcommunity ...' command is used. Try fix by properly interning extcommunities. Also, more generally, make unintern functions take a double pointer so they can NULL out callers references - a usefully defensive programming pattern for functions which make refs invalid. Sadly, this patch doesn't fix the problem entirely - crashes still occur on session clear. * bgp_ecommunity.h: (ecommunity_{free,unintern}) take double pointer args. * bgp_community.h: (community_unintern) ditto * bgp_attr.h: (bgp_attr_intern) ditto * bgp_aspath.h: (bgp_aspath.h) ditto * (general) update all callers of above * bgp_routemap.c: (route_set_ecommunity_{rt,soo}) intern the new extcom added to the attr, and unintern any old one. (route_set_ecommunity_{rt,soo}_compile) intern the extcom to be used for the route-map set. (route_set_ecommunity_*_free) unintern to match, instead of free (route_set_ecommunity_soo) Do as _rt does and don't just leak any pre-existing community, add to it (is additive right though?)
| | * bgpd: Rollback some of the changes made for invalid AS_PATH segment fixPaul Jakma2011-03-213-128/+105
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Some of the changes made in commit cddb8112b80fa9867156c637d63e6e79eeac67bb don't work particularly well for other changes that need to be made to address BGP attribute error handling problems. In particular, returning a pointer from complex attribute data parsing functions will not suffice to express the require range of return status conditions. * bgp_aspath.c: (assegments_parse) Rollback to a more minimal set of changes to fix the original problem. (aspath_parse) Slightly needless pushing around of code, and taking 2 parameters to say whether ot use 2 or 4 byte encoding seems unnecessary. * bgp_attr.c: (bgp_attr_as{,4}path) Rollback, in preparation for BGP attribute error handling update.
* | | bgpd: We try to skip out of updating the multipath aggregate if there are noJosh Bailey2011-07-201-15/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | changes in the multipath set or attributes, but failed to check for just a bestpath change. The result is there is no attribute on the new bestpath and we hit the assert. Added the bestpath check and rearranged the code to only check attributes when there is no bestpath or multipath change, so we only scan the for attribute changes when necessary. * bgpd/bgp_mpath.c * bgp_info_mpath_aggregate_update(): Added check for bestpath change before skipping the aggregate generation. Skip the attribute check if either the multipath set or bestpath has changed.
* | | bgpd: Fix a crash caused by mistakenly dequeueing the bestpath on theJosh Bailey2011-07-201-3/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | multipath list. This causes the multipath list to get truncated but the multipath count still reflects what it was before truncation. When we install the route to zebra we fail to fill the nexthop array with the number of nexthop pointers indicated by the multipath count and this leads to a NULL pointer crash in stream_put_in_addr(). Changes: * bgpd/bgp_mpath.c * bgp_info_mpath_update(): If new_mpath is the bestpath we should just move to the next mp_list node. Move dequeue of new_mpath and the code that updates next_mpath to inside the check that new_mpath is not the bestpath.
* | | bgpd: When advertising a multipath route, the attribute set to beJosh Bailey2011-07-205-17/+218
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | advertised is based on the bestpath attribute set, but the following attributes are aggregated from the attribute sets of the multipath constituents: - AS_PATH - ORIGIN - COMMUNITIES - EXTENDED COMMUNITIES In addition the route is advertised with the NEXT_HOP set to the router's interface IP address, instead of the NEXT_HOP of the best path. This is to ensure that traffic will go to this router so it can be fanned out via the multipath route. * bgpd/ecommunity.c * ecommunity_uniq_sort(): Make this function externally accessible * bgpd/ecommunity.h * Add external declaration for ecommunity_uniq_sort() * bgpd/bgp_mpath.c * bgp_info_nexthop_cmp(): Replace calls to bgp_attr_extra_get() to avoid unwanted memory allocation * bgp_info_mpath_free(): Free aggregate attribute for multipath * bgp_info_mpath_attr(): Lookup aggregate attribute of a multipath route * bgp_info_mpath_attr_set(): Set aggregate attribute of a multipath route * bgp_info_mpath_aggregate_update(): Update the aggregate attribute of a multipath route * bgpd/bgp_mpath.h * bgp_info_mpath: Add pointer to hold aggregate attribute of a multipath * Add external declarations for new functions * bgpd/bgp_route.c * bgp_announce_check(): Use aggregate attribute when announcing multipath route * bgp_announce_check_rsclient(): Use aggregate attribute when announcing multipath route * bgp_best_selection(): After updating multipath set, update the multipath aggregate attribute
* | | bgpd: For deterministic MED build a multipath set for each peer AS as theJosh Bailey2011-07-203-1/+49
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | first stage of the best path calculation. The second stage then selects a winner from each peer AS's best path. In the second stage we clear multipath set of the non-selected best paths via bgp_mp_dmed_deselect(). Since the multipath set is already marked up for the winning path, we don't call bgp_info_mpath_update() after the second stage calculation. * bgpd/bgp_mpath.c * bgp_mp_dmed_deselect(): New function to cleanup the multipath markup if a DMED selected path loses in stage 2 of the best path calculation * bgpd/bgp_mpath.h * Add external declaration of bgp_mp_dmed_deselect() * bgpd/bgp_route.c * bgp_best_selection(): If multipath is enabled, build up the mp_list for the current peer AS, and do the RIB markup the best path from that AS. In the second stage, clear the RIB markup for the DMED selected path if it is not selected as best. Only call bgp_info_mpath_update() in the second stage when not doing deterministic MED.