diff --git a/ui/src/app/components/routes/flags/PrimaryIndicator.js b/ui/src/app/components/routes/flags/PrimaryIndicator.js
new file mode 100644
index 0000000..becc226
--- /dev/null
+++ b/ui/src/app/components/routes/flags/PrimaryIndicator.js
@@ -0,0 +1,15 @@
+
+const PrimaryIndicator = ({route}) => {
+ if (route.primary) {
+ return(
+
+ Best Route
+
+ );
+ }
+ return (
+
+ );
+}
+
+export default PrimaryIndicator;
diff --git a/ui/src/app/components/routes/flags/RejectCandidateIndicator.js b/ui/src/app/components/routes/flags/RejectCandidateIndicator.js
new file mode 100644
index 0000000..8599396
--- /dev/null
+++ b/ui/src/app/components/routes/flags/RejectCandidateIndicator.js
@@ -0,0 +1,29 @@
+
+import { useConfig }
+ from 'app/context/config';
+
+import { isRejectCandidate }
+ from 'app/components/routes/communities';
+
+
+const RejectCandidateIndicator = ({route}) => {
+ const { reject_candidates } = useConfig();
+ const candidateCommunities = reject_candidates.communities;
+
+ if (candidateCommunities) {
+ return null;
+ }
+ if (!isRejectCandidate(candidateCommunities, route)) {
+ return null;
+ }
+
+ const cls = `route-prefix-flag reject-candidate-route`;
+ return (
+
+
+ Reject Candidate
+
+ );
+}
+
+export default RejectCandidateIndicator;
diff --git a/ui/src/app/components/routes/flags/RpkiIndicator.js b/ui/src/app/components/routes/flags/RpkiIndicator.js
new file mode 100644
index 0000000..06919cf
--- /dev/null
+++ b/ui/src/app/components/routes/flags/RpkiIndicator.js
@@ -0,0 +1,91 @@
+
+import { useConfig }
+ from 'app/context/config';
+
+const RpkiIndicator = ({route}) => {
+ const { rpki } = useConfig();
+
+ // Check if indicator is enabled
+ if (rpki.enabled === false) { return null; }
+
+ // Check for BGP large communities as configured in the alice.conf
+ const rpkiValid = rpki.valid;
+ const rpkiUnknown = rpki.unknown;
+ const rpkiNotChecked = rpki.not_checked;
+ const rpkiInvalid = rpki.invalid;
+
+ const communities = route?.bgp?.large_communities;
+ for (const com of communities) {
+ // RPKI VALID
+ if (com[0].toFixed() === rpkiValid[0] &&
+ com[1].toFixed() === rpkiValid[1] &&
+ com[2].toFixed() === rpkiValid[2]) {
+ return (
+
+
+ RPKI Valid
+
+ );
+ }
+
+ // RPKI UNKNOWN
+ if (com[0].toFixed() === rpkiUnknown[0] &&
+ com[1].toFixed() === rpkiUnknown[1] &&
+ com[2].toFixed() === rpkiUnknown[2]) {
+ return (
+
+
+ RPKI Unknown
+
+ );
+ }
+
+ // RPKI NOT CHECKED
+ if (com[0].toFixed() === rpkiNotChecked[0] &&
+ com[1].toFixed() === rpkiNotChecked[1] &&
+ com[2].toFixed() === rpkiNotChecked[2]) {
+ return (
+
+
+ RPKI not checked
+
+ );
+ }
+
+ // RPKI INVALID
+ // Depending on the configration this can either be a
+ // single flag or a range with a given reason.
+ let rpkiInvalidReason = 0;
+ if (com[0].toFixed() === rpkiInvalid[0] &&
+ com[1].toFixed() === rpkiInvalid[1]) {
+
+ // This needs to be considered invalid, now try to detect why
+ if (rpkiInvalid.length > 3 && rpkiInvalid[3] === "*") {
+ // Check if token falls within range
+ const start = parseInt(rpkiInvalid[2], 10);
+ if (com[2] >= start) {
+ rpkiInvalidReason = com[2];
+ }
+ } else {
+ if (com[2].toFixed() === rpkiInvalid[2]) {
+ rpkiInvalidReason = 1;
+ }
+ }
+ }
+
+ // This in invalid, render it!
+ if (rpkiInvalidReason > 0) {
+ const cls = `route-prefix-flag rpki-route rpki-invalid rpki-invalid-${rpkiInvalidReason}`
+ return (
+
+
+ RPKI Invalid
+
+ );
+ }
+ }
+
+ return null;
+}
+
+export default RpkiIndicator;