+ @Override
+ public void onMessage(final BGPSession session, final Notification msg) throws BGPDocumentedException {
+ if (msg instanceof Update) {
+ onUpdateMessage((Update) msg);
+ } else if (msg instanceof RouteRefresh) {
+ onRouteRefreshMessage((RouteRefresh) msg);
+ } else {
+ LOG.info("Ignoring unhandled message class {}", msg.getClass());
+ }
+ }
+
+ private void onRouteRefreshMessage(final RouteRefresh message) {
+ final Class<? extends AddressFamily> rrAfi = message.getAfi();
+ final Class<? extends SubsequentAddressFamily> rrSafi = message.getSafi();
+
+ final TablesKey key = new TablesKey(rrAfi, rrSafi);
+ synchronized (this) {
+ final AdjRibOutListener listener = this.adjRibOutListenerSet.remove(key);
+ if (listener != null) {
+ listener.close();
+ createAdjRibOutListener(key, listener.isMpSupported());
+ } else {
+ LOG.info("Ignoring RouteRefresh message. Afi/Safi is not supported: {}, {}.", rrAfi, rrSafi);
+ }
+ }
+ }
+
+ /**
+ * Check for presence of well known mandatory attribute LOCAL_PREF in Update message.
+ *
+ * @param message Update message
+ */
+ private void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException {
+ if (MessageUtil.isAnyNlriPresent(message)) {
+ final Attributes attrs = message.getAttributes();
+ if (this.peerRole == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) {
+ throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF",
+ BGPError.WELL_KNOWN_ATTR_MISSING,
+ new byte[]{LocalPreferenceAttributeParser.TYPE});
+ }
+ }
+ }
+
+ /**
+ * Process Update message received.
+ * Calls {@link #checkMandatoryAttributesPresence(Update)} to check for presence of mandatory attributes.
+ *
+ * @param message Update message
+ */
+ private synchronized void onUpdateMessage(final Update message) throws BGPDocumentedException {
+ checkMandatoryAttributesPresence(message);
+
+ // update AdjRibs
+ final Attributes attrs = message.getAttributes();
+ MpReachNlri mpReach;
+ final boolean isAnyNlriAnnounced = message.getNlri() != null;
+ if (isAnyNlriAnnounced) {
+ mpReach = prefixesToMpReach(message);
+ } else {
+ mpReach = MessageUtil.getMpReachNlri(attrs);
+ }
+ if (mpReach != null) {
+ this.ribWriter.updateRoutes(mpReach, nextHopToAttribute(attrs, mpReach));
+ }
+ final MpUnreachNlri mpUnreach;
+ if (message.getWithdrawnRoutes() != null) {
+ mpUnreach = prefixesToMpUnreach(message, isAnyNlriAnnounced);
+ } else {
+ mpUnreach = MessageUtil.getMpUnreachNlri(attrs);
+ }
+ final boolean endOfRib = BgpPeerUtil.isEndOfRib(message);
+ if (mpUnreach != null) {
+ if (endOfRib) {
+ final TablesKey tablesKey = new TablesKey(mpUnreach.getAfi(), mpUnreach.getSafi());
+ this.ribWriter.removeStaleRoutes(tablesKey);
+ this.missingEOT.remove(tablesKey);
+ handleGracefulEndOfRib();
+ } else {
+ this.ribWriter.removeRoutes(mpUnreach);
+ }
+ } else if (endOfRib) {
+ this.ribWriter.removeStaleRoutes(IPV4_UCAST_TABLE_KEY);
+ this.missingEOT.remove(IPV4_UCAST_TABLE_KEY);
+ handleGracefulEndOfRib();
+ }
+ }
+
+ @Holding("this")
+ private void handleGracefulEndOfRib() {
+ if (isLocalRestarting()) {
+ if (this.missingEOT.isEmpty()) {
+ createEffRibInWriter();
+ this.effRibInWriter.init();
+ registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
+ for (final TablesKey key : getAfiSafisAdvertized()) {
+ createAdjRibOutListener(key, true);
+ }
+ setLocalRestartingState(false);
+ setGracefulPreferences(false, Collections.emptySet());