IP directed broadcast 61/13561/3
authorNeale Ranns <nranns@cisco.com>
Wed, 11 Jul 2018 17:31:26 +0000 (10:31 -0700)
committerDamjan Marion <dmarion@me.com>
Fri, 20 Jul 2018 13:21:03 +0000 (13:21 +0000)
with ip direct broadcast enable a packet to the interface's
subnet broadcast address with be sent L2 broadcast on the
interface. dissabled, it will be dropped. it is disabled by
default, which preserves current behaviour

Change-Id: If154cb92e64834e97a541b32624354348a0eafb3
Signed-off-by: Neale Ranns <nranns@cisco.com>
18 files changed:
src/plugins/pppoe/pppoe.c
src/vnet/adj/adj.c
src/vnet/adj/adj.h
src/vnet/adj/adj_nbr.c
src/vnet/ethernet/arp.c
src/vnet/interface.api
src/vnet/interface.c
src/vnet/interface.h
src/vnet/interface_api.c
src/vnet/interface_cli.c
src/vnet/interface_funcs.h
src/vnet/ip/ip4.h
src/vnet/ip/ip4_forward.c
src/vnet/ip/ip6_forward.c
src/vnet/ip/ip6_neighbor.c
src/vnet/mpls/mpls_tunnel.c
test/test_ip4.py
test/vpp_papi_provider.py

index dfbe2e4..e5ab5d0 100644 (file)
@@ -184,6 +184,7 @@ pppoe_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
     {
     case IP_LOOKUP_NEXT_ARP:
     case IP_LOOKUP_NEXT_GLEAN:
+    case IP_LOOKUP_NEXT_BCAST:
       adj_nbr_midchain_update_rewrite (ai, pppoe_fixup, t,
                                       ADJ_FLAG_NONE,
                                       pppoe_build_rewrite (vnm,
index 0de3fc8..80a5d05 100644 (file)
@@ -35,6 +35,13 @@ ip_adjacency_t *adj_pool;
  */
 int adj_per_adj_counters;
 
+const ip46_address_t ADJ_BCAST_ADDR = {
+    .ip6 = {
+        .as_u64[0] = 0xffffffffffffffff,
+        .as_u64[1] = 0xffffffffffffffff,
+    },
+};
+
 always_inline void
 adj_poison (ip_adjacency_t * adj)
 {
@@ -172,6 +179,7 @@ adj_last_lock_gone (ip_adjacency_t *adj)
         /* FALL THROUGH */
     case IP_LOOKUP_NEXT_ARP:
     case IP_LOOKUP_NEXT_REWRITE:
+    case IP_LOOKUP_NEXT_BCAST:
        /*
         * complete and incomplete nbr adjs
         */
index fe77d16..18a2e1d 100644 (file)
@@ -81,6 +81,9 @@ typedef enum
   /** Multicast Adjacency. */
   IP_LOOKUP_NEXT_MCAST,
 
+  /** Broadcasr Adjacency. */
+  IP_LOOKUP_NEXT_BCAST,
+
   /** Multicast Midchain Adjacency. An Adjacency for sending macst packets
    *  on a tunnel/virtual interface */
   IP_LOOKUP_NEXT_MCAST_MIDCHAIN,
@@ -110,6 +113,7 @@ typedef enum
     [IP_LOOKUP_NEXT_GLEAN] = "ip4-glean",                      \
     [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite",                  \
     [IP_LOOKUP_NEXT_MCAST] = "ip4-rewrite-mcast",              \
+    [IP_LOOKUP_NEXT_BCAST] = "ip4-rewrite-bcast",               \
     [IP_LOOKUP_NEXT_MIDCHAIN] = "ip4-midchain",                        \
     [IP_LOOKUP_NEXT_MCAST_MIDCHAIN] = "ip4-mcast-midchain",     \
     [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip4-icmp-error",            \
@@ -122,6 +126,7 @@ typedef enum
     [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor",            \
     [IP_LOOKUP_NEXT_GLEAN] = "ip6-glean",                      \
     [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite",                  \
+    [IP_LOOKUP_NEXT_BCAST] = "ip6-rewrite-bcast",              \
     [IP_LOOKUP_NEXT_MCAST] = "ip6-rewrite-mcast",              \
     [IP_LOOKUP_NEXT_MIDCHAIN] = "ip6-midchain",                        \
     [IP_LOOKUP_NEXT_MCAST_MIDCHAIN] = "ip6-mcast-midchain",     \
@@ -131,6 +136,11 @@ typedef enum
     [IP6_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip6-pop-hop-by-hop",   \
 }
 
+/**
+ * The special broadcast address (to construct a broadcast adjacency
+ */
+extern const ip46_address_t ADJ_BCAST_ADDR;
+
 /**
  * Forward delcartion
  */
index 3f66acb..3a474a8 100644 (file)
@@ -230,6 +230,11 @@ adj_nbr_add_or_lock (fib_protocol_t nh_proto,
        adj_index = adj_get_index(adj);
        adj_lock(adj_index);
 
+        if (ip46_address_is_equal(&ADJ_BCAST_ADDR, nh_addr))
+        {
+            adj->lookup_next_index = IP_LOOKUP_NEXT_BCAST;
+        }
+
        vnet_rewrite_init(vnm, sw_if_index, link_type,
                          adj_get_nd_node(nh_proto),
                          vnet_tx_node_index_for_sw_interface(vnm, sw_if_index),
index 09f5661..f7d8ff8 100644 (file)
@@ -492,6 +492,15 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
          arp_nbr_probe (adj);
        }
       break;
+    case IP_LOOKUP_NEXT_BCAST:
+      adj_nbr_update_rewrite (ai,
+                             ADJ_NBR_REWRITE_FLAG_COMPLETE,
+                             ethernet_build_rewrite
+                             (vnm,
+                              sw_if_index,
+                              VNET_LINK_IP4,
+                              VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
+      break;
     case IP_LOOKUP_NEXT_MCAST:
       {
        /*
index 2cbf4f6..b839e89 100644 (file)
@@ -45,6 +45,20 @@ autoreply define sw_interface_set_mtu
   u32 mtu[4]; /* 0 - L3, 1 - IP4, 2 - IP6, 3 - MPLS */
 };
 
+/** \brief Set IP4 directed broadcast
+    The directed broadcast enabled a packet sent to the interface's
+    subnet address will be broadcast on the interface
+    @param sw_if_index
+    @param enable
+*/
+autoreply define sw_interface_set_ip_directed_broadcast
+{
+  u32 client_index;
+  u32 context;
+  u32 sw_if_index;
+  u8  enable;
+};
+
 
 /** \brief Interface Event generated by want_interface_events
     @param client_index - opaque cookie to identify the sender
index a9346a2..ca4dc49 100644 (file)
@@ -705,6 +705,22 @@ vnet_sw_interface_set_protocol_mtu (vnet_main_t * vnm, u32 sw_if_index,
     call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
 }
 
+void
+vnet_sw_interface_ip_directed_broadcast (vnet_main_t * vnm,
+                                        u32 sw_if_index, u8 enable)
+{
+  vnet_sw_interface_t *si;
+
+  si = vnet_get_sw_interface (vnm, sw_if_index);
+
+  if (enable)
+    si->flags |= VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
+  else
+    si->flags &= ~VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
+
+  ip4_directed_broadcast (sw_if_index, enable);
+}
+
 /*
  * Reflect a change in hardware MTU on protocol MTUs
  */
@@ -1609,6 +1625,7 @@ default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
       adj_glean_update_rewrite (ai);
       break;
     case IP_LOOKUP_NEXT_ARP:
+    case IP_LOOKUP_NEXT_BCAST:
       /*
        * default rewirte in neighbour adj
        */
index f82cf9d..d869b0c 100644 (file)
@@ -648,32 +648,40 @@ typedef enum
 
 extern vnet_mtu_t vnet_link_to_mtu (vnet_link_t link);
 
-/* Software-interface.  This corresponds to a Ethernet VLAN, ATM vc, a
-   tunnel, etc.  Configuration (e.g. IP address) gets attached to
-   software interface. */
-typedef struct
+typedef enum vnet_sw_interface_flags_t_
 {
-  vnet_sw_interface_type_t type:16;
-
-  u16 flags;
   /* Interface is "up" meaning adminstratively up.
      Up in the sense of link state being up is maintained by hardware interface. */
-#define VNET_SW_INTERFACE_FLAG_ADMIN_UP (1 << 0)
+  VNET_SW_INTERFACE_FLAG_ADMIN_UP = (1 << 0),
 
   /* Interface is disabled for forwarding: punt all traffic to slow-path. */
-#define VNET_SW_INTERFACE_FLAG_PUNT (1 << 1)
+  VNET_SW_INTERFACE_FLAG_PUNT = (1 << 1),
 
-#define VNET_SW_INTERFACE_FLAG_PROXY_ARP (1 << 2)
+  VNET_SW_INTERFACE_FLAG_PROXY_ARP = (1 << 2),
 
-#define VNET_SW_INTERFACE_FLAG_UNNUMBERED (1 << 3)
+  VNET_SW_INTERFACE_FLAG_UNNUMBERED = (1 << 3),
 
-#define VNET_SW_INTERFACE_FLAG_BOND_SLAVE (1 << 4)
+  VNET_SW_INTERFACE_FLAG_BOND_SLAVE = (1 << 4),
 
   /* Interface does not appear in CLI/API */
-#define VNET_SW_INTERFACE_FLAG_HIDDEN (1 << 5)
+  VNET_SW_INTERFACE_FLAG_HIDDEN = (1 << 5),
 
   /* Interface in ERROR state */
-#define VNET_SW_INTERFACE_FLAG_ERROR (1 << 6)
+  VNET_SW_INTERFACE_FLAG_ERROR = (1 << 6),
+
+  /* Interface has IP configured directed broadcast */
+  VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST = (1 << 7),
+
+} __attribute__ ((packed)) vnet_sw_interface_flags_t;
+
+/* Software-interface.  This corresponds to a Ethernet VLAN, ATM vc, a
+   tunnel, etc.  Configuration (e.g. IP address) gets attached to
+   software interface. */
+typedef struct
+{
+  vnet_sw_interface_type_t type:16;
+
+  vnet_sw_interface_flags_t flags;
 
   /* Index for this interface. */
   u32 sw_if_index;
index e2f4d8f..1d167c6 100644 (file)
@@ -70,7 +70,9 @@ _(CREATE_LOOPBACK, create_loopback)                           \
 _(CREATE_LOOPBACK_INSTANCE, create_loopback_instance)          \
 _(DELETE_LOOPBACK, delete_loopback)                             \
 _(INTERFACE_NAME_RENUMBER, interface_name_renumber)             \
-_(COLLECT_DETAILED_INTERFACE_STATS, collect_detailed_interface_stats)
+_(COLLECT_DETAILED_INTERFACE_STATS, collect_detailed_interface_stats) \
+_(SW_INTERFACE_SET_IP_DIRECTED_BROADCAST,                            \
+  sw_interface_set_ip_directed_broadcast)
 
 static void
 vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp)
@@ -163,6 +165,23 @@ vl_api_sw_interface_set_mtu_t_handler (vl_api_sw_interface_set_mtu_t * mp)
   REPLY_MACRO (VL_API_SW_INTERFACE_SET_MTU_REPLY);
 }
 
+static void
+  vl_api_sw_interface_set_ip_directed_broadcast_t_handler
+  (vl_api_sw_interface_set_ip_directed_broadcast_t * mp)
+{
+  vl_api_sw_interface_set_ip_directed_broadcast_reply_t *rmp;
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  vnet_sw_interface_ip_directed_broadcast (vnet_get_main (),
+                                          sw_if_index, mp->enable);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_IP_DIRECTED_BROADCAST_REPLY);
+}
+
 static void
 send_sw_interface_details (vpe_api_main_t * am,
                           vl_api_registration_t * rp,
index 264c1f3..91725b6 100644 (file)
@@ -1273,6 +1273,46 @@ VLIB_CLI_COMMAND (clear_tag_command, static) = {
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+set_ip_directed_broadcast (vlib_main_t * vm,
+                          unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 sw_if_index = ~0;
+  u8 enable = 0;
+
+  if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index));
+  else if (unformat (input, "enable"))
+    enable = 1;
+  else if (unformat (input, "disable"))
+    enable = 0;
+  else
+    return clib_error_return (0, "unknown input: `%U'",
+                             format_unformat_error, input);
+
+  if (~0 == sw_if_index)
+    return clib_error_return (0, "specify an interface: `%U'",
+                             format_unformat_error, input);
+
+  vnet_sw_interface_ip_directed_broadcast (vnm, sw_if_index, enable);
+
+  return 0;
+}
+
+/*?
+ * This command is used to enable/disable IP directed broadcast
+ * If directed broadcast is enabled a packet sent to the interface's
+ * subnet broadcast address will be sent L2 broadcast on the interface,
+ * otherwise it is dropped.
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_ip_directed_broadcast_command, static) = {
+  .path = "set interface ip directed-broadcast",
+  .short_help = "set interface enable <interface> <enable|disable>",
+  .function = set_ip_directed_broadcast,
+};
+/* *INDENT-ON* */
+
 static clib_error_t *
 set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
                          u32 queue_id, vnet_hw_interface_rx_mode mode)
index 206bfbe..a8a41e3 100644 (file)
@@ -224,7 +224,7 @@ void vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index);
 void vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index);
 int vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index);
 
-always_inline uword
+always_inline vnet_sw_interface_flags_t
 vnet_sw_interface_get_flags (vnet_main_t * vnm, u32 sw_if_index)
 {
   vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
@@ -368,6 +368,8 @@ void vnet_sw_interface_update_unnumbered (u32 sw_if_index,
 
 int vnet_sw_interface_stats_collect_enable_disable (u32 sw_if_index,
                                                    u8 enable);
+void vnet_sw_interface_ip_directed_broadcast (vnet_main_t * vnm,
+                                             u32 sw_if_index, u8 enable);
 
 /* Formats sw/hw interface. */
 format_function_t format_vnet_hw_interface;
index 8187a9d..fcef559 100644 (file)
@@ -245,6 +245,8 @@ clib_error_t *ip4_add_del_interface_address (vlib_main_t * vm,
                                             ip4_address_t * address,
                                             u32 address_length, u32 is_del);
 
+void ip4_directed_broadcast (u32 sw_if_index, u8 enable);
+
 void ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable);
 
 int ip4_address_compare (ip4_address_t * a1, ip4_address_t * a2);
index fd8559d..000710e 100644 (file)
@@ -340,6 +340,45 @@ ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
   return result;
 }
 
+static void
+ip4_add_subnet_bcast_route (u32 fib_index,
+                            fib_prefix_t *pfx,
+                            u32 sw_if_index)
+{
+  vnet_sw_interface_flags_t iflags;
+
+  iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
+
+  fib_table_entry_special_remove(fib_index,
+                                 pfx,
+                                 FIB_SOURCE_INTERFACE);
+
+  if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
+    {
+      fib_table_entry_update_one_path (fib_index, pfx,
+                                       FIB_SOURCE_INTERFACE,
+                                       FIB_ENTRY_FLAG_NONE,
+                                       DPO_PROTO_IP4,
+                                       /* No next-hop address */
+                                       &ADJ_BCAST_ADDR,
+                                       sw_if_index,
+                                       // invalid FIB index
+                                       ~0,
+                                       1,
+                                       // no out-label stack
+                                       NULL,
+                                       FIB_ROUTE_PATH_FLAG_NONE);
+    }
+  else
+    {
+        fib_table_entry_special_add(fib_index,
+                                    pfx,
+                                    FIB_SOURCE_INTERFACE,
+                                    (FIB_ENTRY_FLAG_DROP |
+                                     FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
+    }
+}
+
 static void
 ip4_add_interface_routes (u32 sw_if_index,
                          ip4_main_t * im, u32 fib_index,
@@ -385,11 +424,7 @@ ip4_add_interface_routes (u32 sw_if_index,
                                      FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
       net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
       if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
-        fib_table_entry_special_add(fib_index,
-                                    &net_pfx,
-                                    FIB_SOURCE_INTERFACE,
-                                    (FIB_ENTRY_FLAG_DROP |
-                                     FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
+        ip4_add_subnet_bcast_route(fib_index, &net_pfx, sw_if_index);
     }
   else if (pfx.fp_len == 31)
     {
@@ -637,6 +672,45 @@ ip4_add_del_interface_address (vlib_main_t * vm,
     (vm, sw_if_index, address, address_length, is_del);
 }
 
+void
+ip4_directed_broadcast (u32 sw_if_index, u8 enable)
+{
+  ip_interface_address_t *ia;
+  ip4_main_t *im;
+
+  im = &ip4_main;
+
+  /*
+   * when directed broadcast is enabled, the subnet braodcast route will forward
+   * packets using an adjacency with a broadcast MAC. otherwise it drops
+   */
+  /* *INDENT-OFF* */
+  foreach_ip_interface_address(&im->lookup_main, ia,
+                               sw_if_index, 0,
+     ({
+       if (ia->address_length <= 30)
+         {
+           ip4_address_t *ipa;
+
+           ipa = ip_interface_address_get_address (&im->lookup_main, ia);
+
+           fib_prefix_t pfx = {
+             .fp_len = 32,
+             .fp_proto = FIB_PROTOCOL_IP4,
+             .fp_addr = {
+               .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
+             },
+           };
+
+           ip4_add_subnet_bcast_route
+             (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
+                                                  sw_if_index),
+              &pfx, sw_if_index);
+         }
+     }));
+  /* *INDENT-ON* */
+}
+
 /* Built-in ip4 unicast rx feature path definition */
 /* *INDENT-OFF* */
 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
@@ -2521,6 +2595,16 @@ ip4_rewrite (vlib_main_t * vm,
     return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
 }
 
+static uword
+ip4_rewrite_bcast (vlib_main_t * vm,
+                  vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (adj_are_counters_enabled ())
+    return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
+  else
+    return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
+}
+
 static uword
 ip4_midchain (vlib_main_t * vm,
              vlib_node_runtime_t * node, vlib_frame_t * frame)
@@ -2566,7 +2650,16 @@ VLIB_REGISTER_NODE (ip4_rewrite_node) = {
     [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
   },
 };
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
+
+VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
+  .function = ip4_rewrite,
+  .name = "ip4-rewrite-bcast",
+  .vector_size = sizeof (u32),
+
+  .format_trace = format_ip4_rewrite_trace,
+  .sibling_of = "ip4-rewrite",
+};
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_bcast_node, ip4_rewrite_bcast)
 
 VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
   .function = ip4_rewrite_mcast,
index 41f5b15..888b526 100644 (file)
@@ -1943,6 +1943,16 @@ ip6_rewrite (vlib_main_t * vm,
     return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
 }
 
+static uword
+ip6_rewrite_bcast (vlib_main_t * vm,
+                  vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (adj_are_counters_enabled ())
+    return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
+  else
+    return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
+}
+
 static uword
 ip6_rewrite_mcast (vlib_main_t * vm,
                   vlib_node_runtime_t * node, vlib_frame_t * frame)
@@ -1982,11 +1992,9 @@ VLIB_REGISTER_NODE (ip6_midchain_node) =
   .format_trace = format_ip6_forward_next_trace,
   .sibling_of = "ip6-rewrite",
   };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ip6_rewrite_node) =
 {
   .function = ip6_rewrite,
@@ -2001,11 +2009,19 @@ VLIB_REGISTER_NODE (ip6_rewrite_node) =
     [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
   },
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
 
-/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
+  .function = ip6_rewrite,
+  .name = "ip6-rewrite-bcast",
+  .vector_size = sizeof (u32),
+
+  .format_trace = format_ip6_rewrite_trace,
+  .sibling_of = "ip6-rewrite",
+};
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_bcast_node, ip6_rewrite_bcast)
+
 VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
 {
   .function = ip6_rewrite_mcast,
@@ -2014,11 +2030,9 @@ VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
   .format_trace = format_ip6_rewrite_trace,
   .sibling_of = "ip6-rewrite",
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
 {
   .function = ip6_mcast_midchain,
@@ -2027,9 +2041,9 @@ VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
   .format_trace = format_ip6_rewrite_trace,
   .sibling_of = "ip6-rewrite",
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
+/* *INDENT-ON* */
 
 /*
  * Hop-by-Hop handling
index a6227fc..7c7a706 100644 (file)
@@ -662,6 +662,14 @@ ip6_ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
          ip6_nbr_probe (adj);
        }
       break;
+    case IP_LOOKUP_NEXT_BCAST:
+      adj_nbr_update_rewrite (ai,
+                             ADJ_NBR_REWRITE_FLAG_COMPLETE,
+                             ethernet_build_rewrite (vnm,
+                                                     sw_if_index,
+                                                     VNET_LINK_IP6,
+                                                     VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
+      break;
     case IP_LOOKUP_NEXT_MCAST:
       {
        /*
index a142edf..d3faeac 100644 (file)
@@ -399,6 +399,7 @@ mpls_tunnel_update_adj (vnet_main_t * vnm,
     {
     case IP_LOOKUP_NEXT_ARP:
     case IP_LOOKUP_NEXT_GLEAN:
+    case IP_LOOKUP_NEXT_BCAST:
         adj_nbr_midchain_update_rewrite(ai, mpls_tunnel_fixup,
                                         NULL,
                                         ADJ_FLAG_NONE,
index 2d98ed5..e501bff 100644 (file)
@@ -1392,5 +1392,74 @@ class TestIPInput(VppTestCase):
         # Reset MTU for subsequent tests
         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
 
+
+class TestIPDirectedBroadcast(VppTestCase):
+    """ IPv4 Directed Broadcast """
+
+    def setUp(self):
+        super(TestIPDirectedBroadcast, self).setUp()
+
+        self.create_pg_interfaces(range(2))
+
+        for i in self.pg_interfaces:
+            i.admin_up()
+
+    def tearDown(self):
+        super(TestIPDirectedBroadcast, self).tearDown()
+        for i in self.pg_interfaces:
+            i.admin_down()
+
+    def test_ip_input(self):
+        """ IP Directed Broadcast """
+
+        #
+        # set the directed broadcast on pg0 first, then config IP4 addresses
+        # for pg1 directed broadcast is always disabled
+        self.vapi.sw_interface_set_ip_directed_broadcast(
+            self.pg0.sw_if_index, 1)
+
+        p0 = (Ether(src=self.pg1.remote_mac,
+                    dst=self.pg1.local_mac) /
+              IP(src="1.1.1.1",
+                 dst=self.pg0._local_ip4_bcast) /
+              UDP(sport=1234, dport=1234) /
+              Raw('\xa5' * 2000))
+        p1 = (Ether(src=self.pg0.remote_mac,
+                    dst=self.pg0.local_mac) /
+              IP(src="1.1.1.1",
+                 dst=self.pg1._local_ip4_bcast) /
+              UDP(sport=1234, dport=1234) /
+              Raw('\xa5' * 2000))
+
+        self.pg0.config_ip4()
+        self.pg0.resolve_arp()
+        self.pg1.config_ip4()
+        self.pg1.resolve_arp()
+
+        #
+        # test packet is L2 broadcast
+        #
+        rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
+        self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
+
+        self.send_and_assert_no_replies(self.pg0, p1 * 65,
+                                        "directed broadcast disabled")
+
+        #
+        # toggle directed broadcast on pg0
+        #
+        self.vapi.sw_interface_set_ip_directed_broadcast(
+            self.pg0.sw_if_index, 0)
+        self.send_and_assert_no_replies(self.pg1, p0 * 65,
+                                        "directed broadcast disabled")
+
+        self.vapi.sw_interface_set_ip_directed_broadcast(
+            self.pg0.sw_if_index, 1)
+        rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
+
+        self.pg0.unconfig_ip4()
+        self.pg1.unconfig_ip4()
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index 5383b07..6ea1d2f 100644 (file)
@@ -720,6 +720,18 @@ class VppPapiProvider(object):
                         {'sw_if_index': sw_if_index,
                          'enable': enable})
 
+    def sw_interface_set_ip_directed_broadcast(
+            self,
+            sw_if_index,
+            enable=1):
+        """IP Directed broadcast
+        :param sw_if_index - interface the operation is applied to
+
+        """
+        return self.api(self.papi.sw_interface_set_ip_directed_broadcast,
+                        {'sw_if_index': sw_if_index,
+                         'enable': enable})
+
     def sw_interface_set_flags(self, sw_if_index, admin_up_down):
         """