]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: Fix Attach-bit processing
authorlynne <lynne@voltanet.io>
Thu, 24 Dec 2020 18:29:42 +0000 (13:29 -0500)
committerlynne <lynne@voltanet.io>
Wed, 20 Jan 2021 14:24:35 +0000 (09:24 -0500)
The purpose of the Attach-bit is to accomplish inter-area routing.  In other
venders, the Attached-bit is automatically set when a router is configured
as a L1|L2 router and has two adjacencies.  When a L1 router receives a LSP
with the Attached-bit set it is supposed to create a default route pointing
toward the neighbor to provide a default path out of the L1 area.

ISIS implementation has been fixed to support the above definition:
Setting the Attach-bit is now the default behavior and we allow the user to
turn it off.

We will only set the Default Attach-bit when creating a L1 LSP, if we are
a L1|L2 router and have a L2 adjacency up.

When a L1 router receives a LSP with the Attach-bit set, we will create a
default route pointing to the L1|L2 router as the nexthop.

The default route will be removed if the LSP is received with the Attach-bit
cleared.

Signed-off-by: Lynne Morrison <lynne@voltanet.io>
isisd/isis_cli.c
isisd/isis_constants.h
isisd/isis_lsp.c
isisd/isis_nb.c
isisd/isis_nb.h
isisd/isis_nb_config.c
isisd/isis_pdu.c
isisd/isis_spf.c
isisd/isisd.c
isisd/isisd.h
yang/frr-isisd.yang

index 5ca70eab0f88ca81b7aa488f61ba1fbc249c79f3..b48da9312fc973c3bc771ff81a94954334dd7d2b 100644 (file)
@@ -593,6 +593,10 @@ void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode,
        vty_out(vty, " set-overload-bit\n");
 }
 
+#if CONFDATE > 20220119
+CPP_NOTICE(
+       "Use of `set-attached-bit` is deprecated please use attached-bit [send | receive]")
+#endif
 /*
  * XPath: /frr-isisd:isis/instance/attached
  */
@@ -600,18 +604,57 @@ DEFPY_YANG(set_attached_bit, set_attached_bit_cmd, "[no] set-attached-bit",
       "Reset attached bit\n"
       "Set attached bit to identify as L1/L2 router for inter-area traffic\n")
 {
-       nb_cli_enqueue_change(vty, "./attached", NB_OP_MODIFY,
+       vty_out(vty,
+               "set-attached-bit deprecated please use attached-bit [send | receive]\n");
+
+       return CMD_SUCCESS;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/attach-send
+ */
+DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send",
+          "Reset attached bit\n"
+          "Set attached bit for inter-area traffic\n"
+          "Set attached bit in LSP sent to L1 router\n")
+{
+       nb_cli_enqueue_change(vty, "./attach-send", NB_OP_MODIFY,
                              no ? "false" : "true");
 
        return nb_cli_apply_changes(vty, NULL);
 }
 
-void cli_show_isis_attached(struct vty *vty, struct lyd_node *dnode,
-                           bool show_defaults)
+void cli_show_isis_attached_send(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults)
+{
+       if (!yang_dnode_get_bool(dnode, NULL))
+               vty_out(vty, " no");
+       vty_out(vty, " attached-bit send\n");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/attach-receive-ignore
+ */
+DEFPY_YANG(
+       attached_bit_receive_ignore, attached_bit_receive_ignore_cmd,
+       "[no] attached-bit receive ignore",
+       "Reset attached bit\n"
+       "Set attach bit for inter-area traffic\n"
+       "If LSP received with attached bit set, create default route to neighbor\n"
+       "Do not process attached bit\n")
+{
+       nb_cli_enqueue_change(vty, "./attach-receive-ignore", NB_OP_MODIFY,
+                             no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_attached_receive(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults)
 {
        if (!yang_dnode_get_bool(dnode, NULL))
                vty_out(vty, " no");
-       vty_out(vty, " set-attached-bit\n");
+       vty_out(vty, " attached-bit receive ignore\n");
 }
 
 /*
@@ -3206,6 +3249,8 @@ void isis_cli_init(void)
 
        install_element(ISIS_NODE, &set_overload_bit_cmd);
        install_element(ISIS_NODE, &set_attached_bit_cmd);
+       install_element(ISIS_NODE, &attached_bit_send_cmd);
+       install_element(ISIS_NODE, &attached_bit_receive_ignore_cmd);
 
        install_element(ISIS_NODE, &metric_style_cmd);
        install_element(ISIS_NODE, &no_metric_style_cmd);
index 25eae06cb0af0d473957bb1232fd2ac486aded13..3d6a20ee6614cdf62085e66cd12262518d2157e7 100644 (file)
  * LSP bit masks
  */
 #define LSPBIT_P   0x80
-#define LSPBIT_ATT 0x78
+#define LSPBIT_ATT 0x08 /* only use the Default ATT bit */
 #define LSPBIT_OL  0x04
 #define LSPBIT_IST 0x03
 
 #define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
 #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
 #define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
-#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
 
 #define LLC_LEN 3
 
index 47225ea2c3553f1425a36532ad137d0bfdad863e..4c70bd12b72e0990953717015ed77b8a04324299 100644 (file)
@@ -399,7 +399,50 @@ static void lsp_seqno_update(struct isis_lsp *lsp0)
        return;
 }
 
-static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
+static bool isis_level2_adj_up(struct isis_area *curr_area)
+{
+       struct listnode *node, *cnode;
+       struct isis_circuit *circuit;
+       struct list *adjdb;
+       struct isis_adjacency *adj;
+       struct isis *isis = curr_area->isis;
+       struct isis_area *area;
+
+       /* lookup for a Level2 adjacency up in another area */
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+               if (area->area_tag
+                   && strcmp(area->area_tag, curr_area->area_tag) == 0)
+                       continue;
+
+               for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
+                       if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+                               adjdb = circuit->u.bc.adjdb[1];
+                               if (adjdb && adjdb->count) {
+                                       for (ALL_LIST_ELEMENTS_RO(adjdb, node,
+                                                                 adj))
+                                               if ((adj->level
+                                                            == ISIS_ADJ_LEVEL2
+                                                    || adj->level
+                                                               == ISIS_ADJ_LEVEL1AND2)
+                                                   && adj->adj_state
+                                                              == ISIS_ADJ_UP)
+                                                       return true;
+                               }
+                       } else if (circuit->circ_type == CIRCUIT_T_P2P
+                                  && circuit->u.p2p.neighbor) {
+                               adj = circuit->u.p2p.neighbor;
+                               if ((adj->level == ISIS_ADJ_LEVEL2
+                                    || adj->level == ISIS_ADJ_LEVEL1AND2)
+                                   && adj->adj_state == ISIS_ADJ_UP)
+                                       return true;
+                       }
+               }
+       }
+       return false;
+}
+
+static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit,
+                                struct isis_area *area)
 {
        uint8_t lsp_bits = 0;
        if (level == IS_LEVEL_1)
@@ -408,8 +451,13 @@ static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
                lsp_bits = IS_LEVEL_1_AND_2;
        if (overload_bit)
                lsp_bits |= overload_bit;
-       if (attached_bit)
-               lsp_bits |= attached_bit;
+
+       /* only set the attach bit if we are a level-1-2 router and this is
+        * a level-1 LSP and we have a level-2 adjacency up from another area
+        */
+       if (area->is_type == IS_LEVEL_1_AND_2 && level == IS_LEVEL_1
+           && attached_bit && isis_level2_adj_up(area))
+               lsp_bits |= LSPBIT_ATT;
        return lsp_bits;
 }
 
@@ -632,13 +680,13 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
                return " error";
 
        /* we only focus on the default metric */
-       pos += sprintf(pos, "%d/",
-                      ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0);
+       pos += snprintf(pos, buf_size, "%d/",
+                       ISIS_MASK_LSP_ATT_BITS(lsp_bits) ? 1 : 0);
 
-       pos += sprintf(pos, "%d/",
-                      ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
+       pos += snprintf(pos, buf_size, "%d/",
+                       ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
 
-       sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
+       snprintf(pos, buf_size, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
 
        return buf;
 }
@@ -838,7 +886,7 @@ static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
 
        lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0,
                      lsp_bits_generate(level, area->overload_bit,
-                                       area->attached_bit),
+                                       area->attached_bit_send, area),
                      0, lsp0, level);
        lsp->own_lsp = 1;
        lsp_insert(&area->lspdb[level - 1], lsp);
@@ -864,7 +912,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                  area->area_tag, level);
 
        lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
-                                             area->attached_bit);
+                                             area->attached_bit_send, area);
 
        lsp_add_auth(lsp);
 
@@ -1223,10 +1271,10 @@ int lsp_generate(struct isis_area *area, int level)
                                       oldlsp->hdr.lsp_id);
        }
        rem_lifetime = lsp_rem_lifetime(area, level);
-       newlsp =
-               lsp_new(area, lspid, rem_lifetime, seq_num,
-                       area->is_type | area->overload_bit | area->attached_bit,
-                       0, NULL, level);
+       newlsp = lsp_new(area, lspid, rem_lifetime, seq_num,
+                        lsp_bits_generate(area->is_type, area->overload_bit,
+                                          area->attached_bit_send, area),
+                        0, NULL, level);
        newlsp->area = area;
        newlsp->own_lsp = 1;
 
@@ -1310,8 +1358,9 @@ static int lsp_regenerate(struct isis_area *area, int level)
                        continue;
                }
 
-               frag->hdr.lsp_bits = lsp_bits_generate(
-                       level, area->overload_bit, area->attached_bit);
+               frag->hdr.lsp_bits =
+                       lsp_bits_generate(level, area->overload_bit,
+                                         area->attached_bit_send, area);
                /* Set the lifetime values of all the fragments to the same
                 * value,
                 * so that no fragment expires before the lsp is refreshed.
@@ -1518,8 +1567,8 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
 
        lsp->level = level;
        /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-       lsp->hdr.lsp_bits =
-               lsp_bits_generate(level, 0, circuit->area->attached_bit);
+       lsp->hdr.lsp_bits = lsp_bits_generate(
+               level, 0, circuit->area->attached_bit_send, area);
 
        /*
         * add self to IS neighbours
@@ -1617,8 +1666,10 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
        rem_lifetime = lsp_rem_lifetime(circuit->area, level);
        /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
        lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
-                     circuit->area->is_type | circuit->area->attached_bit, 0,
-                     NULL, level);
+                     lsp_bits_generate(circuit->area->is_type, 0,
+                                       circuit->area->attached_bit_send,
+                                       circuit->area),
+                     0, NULL, level);
        lsp->area = circuit->area;
 
        lsp_build_pseudo(lsp, circuit, level);
index a02e6a45b183139440a2d1baed04e70b589a2a44..6d46e6b67e97408bbc9e734254fd380cd9dcfca8 100644 (file)
@@ -59,10 +59,23 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_dynamic_hostname_modify,
                        },
                },
+               {
+                       .xpath = "/frr-isisd:isis/instance/attach-send",
+                       .cbs = {
+                               .cli_show = cli_show_isis_attached_send,
+                               .modify = isis_instance_attached_send_modify,
+                       },
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/attach-receive-ignore",
+                       .cbs = {
+                               .cli_show = cli_show_isis_attached_receive,
+                               .modify = isis_instance_attached_receive_modify,
+                       },
+               },
                {
                        .xpath = "/frr-isisd:isis/instance/attached",
                        .cbs = {
-                               .cli_show = cli_show_isis_attached,
                                .modify = isis_instance_attached_modify,
                        },
                },
index 679bc6345dd79b9c267713a11dc39c261564e2ab..8ecd8134e6dc3c957788c2eb4dcc3f01d4bfcd97 100644 (file)
@@ -34,6 +34,8 @@ int isis_instance_is_type_modify(struct nb_cb_modify_args *args);
 int isis_instance_area_address_create(struct nb_cb_create_args *args);
 int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args);
 int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args);
+int isis_instance_attached_send_modify(struct nb_cb_modify_args *args);
+int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args);
 int isis_instance_attached_modify(struct nb_cb_modify_args *args);
 int isis_instance_overload_modify(struct nb_cb_modify_args *args);
 int isis_instance_metric_style_modify(struct nb_cb_modify_args *args);
@@ -424,8 +426,10 @@ void cli_show_isis_is_type(struct vty *vty, struct lyd_node *dnode,
                           bool show_defaults);
 void cli_show_isis_dynamic_hostname(struct vty *vty, struct lyd_node *dnode,
                                    bool show_defaults);
-void cli_show_isis_attached(struct vty *vty, struct lyd_node *dnode,
-                           bool show_defaults);
+void cli_show_isis_attached_send(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults);
+void cli_show_isis_attached_receive(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
 void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode,
                            bool show_defaults);
 void cli_show_isis_metric_style(struct vty *vty, struct lyd_node *dnode,
index ed0fea88249c846ec03ca87ceb23fa9abc1ff09b..45bbc9737bf5270c2e4a98bd8e0158c6d32aba99 100644 (file)
@@ -272,9 +272,9 @@ int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args)
 }
 
 /*
- * XPath: /frr-isisd:isis/instance/attached
+ * XPath: /frr-isisd:isis/instance/attach-send
  */
-int isis_instance_attached_modify(struct nb_cb_modify_args *args)
+int isis_instance_attached_send_modify(struct nb_cb_modify_args *args)
 {
        struct isis_area *area;
        bool attached;
@@ -284,11 +284,37 @@ int isis_instance_attached_modify(struct nb_cb_modify_args *args)
 
        area = nb_running_get_entry(args->dnode, NULL, true);
        attached = yang_dnode_get_bool(args->dnode, NULL);
-       isis_area_attached_bit_set(area, attached);
+       isis_area_attached_bit_send_set(area, attached);
 
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/attach-receive-ignore
+ */
+int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       bool attached;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       attached = yang_dnode_get_bool(args->dnode, NULL);
+       isis_area_attached_bit_receive_set(area, attached);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/attached
+ */
+int isis_instance_attached_modify(struct nb_cb_modify_args *args)
+{
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-isisd:isis/instance/overload
  */
index 72de5d6543fa3625eba453721a1845da9897d592..2d68aaa9ed6ef1cedc786e83fd8b1aa9091816e5 100644 (file)
@@ -729,8 +729,8 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
 
        if (!memcmp(iih.sys_id, circuit->isis->sysid, ISIS_SYS_ID_LEN)) {
                zlog_warn(
-                       "ISIS-Adj (%s): Received IIH with own sysid - discard",
-                       circuit->area->area_tag);
+                       "ISIS-Adj (%s): Received IIH with own sysid on %s - discard",
+                       circuit->area->area_tag, circuit->interface->name);
                circuit->rej_adjacencies++;
 #ifndef FABRICD
                isis_notif_reject_adjacency(
index dee082fce1e9df4fb13c8bb8031092aef2f82ce0..ec0313f21e2aca11611788ce584f2e7a500342fb 100644 (file)
@@ -1046,6 +1046,32 @@ lspfragloop:
        }
 
 end:
+
+       /* if attach bit set and we are a level-1 router
+        * and attach-bit-rcv-ignore is not configured
+        * add a default route toward this neighbor
+        */
+       if ((lsp->hdr.lsp_bits & LSPBIT_ATT) == LSPBIT_ATT
+           && !spftree->area->attached_bit_rcv_ignore
+           && spftree->area->is_type == IS_LEVEL_1) {
+               struct prefix_pair ip_info = { {0} };
+               if (IS_DEBUG_SPF_EVENTS)
+                       zlog_debug("ISIS-Spf (%s): add default %s route",
+                                  rawlspid_print(lsp->hdr.lsp_id),
+                                  spftree->family == AF_INET ? "ipv4"
+                                                             : "ipv6");
+
+               if (spftree->family == AF_INET) {
+                       ip_info.dest.family = AF_INET;
+                       vtype = VTYPE_IPREACH_INTERNAL;
+               } else {
+                       ip_info.dest.family = AF_INET6;
+                       vtype = VTYPE_IP6REACH_INTERNAL;
+               }
+               process_N(spftree, vtype, &ip_info, cost, depth + 1, NULL,
+                         parent);
+       }
+
        if (fragnode == NULL)
                fragnode = listhead(lsp->lspu.frags);
        else
index eabebab4e000c3bc2b4bf5611ce88a6b987bc0b8..d45690f4dc8dd575c1064afb51fa4c10517fa348 100644 (file)
@@ -316,6 +316,11 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
                "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing");
        area->lfa_load_sharing[1] = yang_get_default_bool(
                "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing");
+       area->attached_bit_send =
+               yang_get_default_bool("/frr-isisd:isis/instance/attach-send");
+       area->attached_bit_rcv_ignore = yang_get_default_bool(
+               "/frr-isisd:isis/instance/attach-receive-ignore");
+
 #else
        area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME;    /* 1200 */
        area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME;    /* 1200 */
@@ -332,6 +337,8 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
        area->lsp_mtu = DEFAULT_LSP_MTU;
        area->lfa_load_sharing[0] = true;
        area->lfa_load_sharing[1] = true;
+       area->attached_bit_send = true;
+       area->attached_bit_rcv_ignore = false;
 #endif /* ifndef FABRICD */
        area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW;
        area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW;
@@ -2547,12 +2554,21 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
 #endif /* ifndef FABRICD */
 }
 
-void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit)
+void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit)
+{
+
+       if (attached_bit != area->attached_bit_send) {
+               area->attached_bit_send = attached_bit;
+               lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+       }
+}
+
+void isis_area_attached_bit_receive_set(struct isis_area *area,
+                                       bool attached_bit)
 {
-       char new_attached_bit = attached_bit ? LSPBIT_ATT : 0;
 
-       if (new_attached_bit != area->attached_bit) {
-               area->attached_bit = new_attached_bit;
+       if (attached_bit != area->attached_bit_rcv_ignore) {
+               area->attached_bit_rcv_ignore = attached_bit;
                lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1);
        }
 }
index 9b903eed48098be08b8d638fbfa855fee46420c6..a09f7415228e869068bdafc24e8c1c897919badb 100644 (file)
@@ -169,7 +169,8 @@ struct isis_area {
        /* are we overloaded? */
        char overload_bit;
        /* L1/L2 router identifier for inter-area traffic */
-       char attached_bit;
+       char attached_bit_send;
+       char attached_bit_rcv_ignore;
        uint16_t lsp_refresh[ISIS_LEVELS];
        /* minimum time allowed before lsp retransmission */
        uint16_t lsp_gen_interval[ISIS_LEVELS];
@@ -253,7 +254,9 @@ void isis_area_invalidate_routes(struct isis_area *area, int levels);
 void isis_area_verify_routes(struct isis_area *area);
 
 void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
-void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit);
+void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit);
+void isis_area_attached_bit_receive_set(struct isis_area *area,
+                                       bool attached_bit);
 void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname);
 void isis_area_metricstyle_set(struct isis_area *area, bool old_metric,
                               bool new_metric);
index 812dd4159d7b49814b57f9f96900bac5e8feea5d..8757ab6b8b2e74a014e2170a237febef901fb5ce 100644 (file)
@@ -1043,9 +1043,24 @@ module frr-isisd {
           "Dynamic hostname support for IS-IS.";
       }
 
+      leaf attach-send {
+        type boolean;
+        default "true";
+        description
+          "If true, attached bits are sent in LSP if L1/L2 router for inter-area traffic.";
+      }
+
+      leaf attach-receive-ignore {
+        type boolean;
+        default "false";
+        description
+          "If false, attached bits received in LSP, cause default route add, if L1 router for inter-area traffic.";
+      }
+
       leaf attached {
         type boolean;
         default "false";
+       status deprecated;
         description
           "If true, identify as L1/L2 router for inter-area traffic.";
       }