Skip to content

Commit 9226e84

Browse files
committed
Remove incorrect \_ in posts.
Showing up wrong, e.g., here: https://batfish.org/2020/12/18/validating-the-validator.html commit-id:b76fefb5
1 parent 023b39d commit 9226e84

8 files changed

+38
-38
lines changed

_posts/2017-11-27-dont-accidentally-break-internet-like-level-three.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ To detect the error before deploying the buggy configuration to the network, the
5151
```
5252
batfish> get bgpAdvertisements differential=true
5353
54-
+ EBGP\_SENT dstIp:192.168.51.2 **srcNode:as65000\_R1** srcIp:192.168.51.1 **net:10.1.1.0/24** nhip:192.168.51.1 origin:INCOMPLETE asPath:\[65000, 65001\] communities:\[4259840002, 4259840010\] orIp:192.168.51.1
54+
+ EBGP_SENT dstIp:192.168.51.2 **srcNode:as65000_R1** srcIp:192.168.51.1 **net:10.1.1.0/24** nhip:192.168.51.1 origin:INCOMPLETE asPath:\[65000, 65001\] communities:\[4259840002, 4259840010\] orIp:192.168.51.1
5555
56-
+ EBGP\_SENT dstIp:192.168.51.2 **srcNode:as65000\_R1** srcIp:192.168.51.1 **net:10.1.2.0/24** nhip:192.168.51.1 origin:INCOMPLETE asPath:\[65000, 65001\] communities:\[4259840002, 4259840010\] orIp:192.168.51.1
56+
+ EBGP_SENT dstIp:192.168.51.2 **srcNode:as65000_R1** srcIp:192.168.51.1 **net:10.1.2.0/24** nhip:192.168.51.1 origin:INCOMPLETE asPath:\[65000, 65001\] communities:\[4259840002, 4259840010\] orIp:192.168.51.1
5757
```
5858

5959
The output shows that **R1** announces two /24 routes only in the second configuration (indicated by ‘+’), a red flag if the change was never intended to leak such routes. Had it shown no routes, or only routes expected due to the change, the configuration can be deemed safe to deploy (assuming other correctness checks pass too).
@@ -63,7 +63,7 @@ The output shows that **R1** announces two /24 routes only in the second config
6363
```
6464
batfish> get bgpAdvertisements prefixSpace=\["10.1.1.0/24:0-23"\]
6565
66-
EBGP\_SENT dstIp:192.168.51.2 **srcNode:as65000\_R1** srcIp:192.168.51.1 **net:10.1.0.0/16** nhip:192.168.51.1 origin:INCOMPLETE asPath:\[65000, 65001\] communities:\[4259840002\] orIp:192.168.51.1
66+
EBGP_SENT dstIp:192.168.51.2 **srcNode:as65000_R1** srcIp:192.168.51.1 **net:10.1.0.0/16** nhip:192.168.51.1 origin:INCOMPLETE asPath:\[65000, 65001\] communities:\[4259840002\] orIp:192.168.51.1
6767
```
6868

6969
The output shows that there is indeed a less specific route (10.1.0.0/16) covering the more specifics.

_posts/2019-06-14-announcing-batfish-ansible.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ To extract “facts” (config settings) from configuration files, one can simpl
3131
- name: Setup connection to Batfish service
3232
bf_session:
3333
host: localhost
34-
name: local\_batfish
34+
name: local_batfish
3535
3636
- name: Initialize the example network
3737
bf_init_snapshot:
@@ -108,7 +108,7 @@ Those advantages aside, the real power of Batfish is in being able to _validate_
108108

109109
## Use case II: Fact validation
110110

111-
Validating that facts in device configs match what is expected is easy with the  **_bf\_validate\_facts_** module.
111+
Validating that facts in device configs match what is expected is easy with the  **_bf_validate_facts_** module.
112112

113113
```
114114
- name: Validate facts gathered by Batfish
@@ -150,7 +150,7 @@ Beyond parsing configs, Batfish builds a full model of device configurations and
150150
name: Confirm that there are NO undefined references on any network device
151151
```
152152

153-
The task above includes four example assertions from our assertion library. The _**bf\_assert**_ module includes more, and based on community feedback, we’ll continue to make more of Batfish’s capabilities available this manner.
153+
The task above includes four example assertions from our assertion library. The _**bf_assert**_ module includes more, and based on community feedback, we’ll continue to make more of Batfish’s capabilities available this manner.
154154

155155
Today’s release makes network validating broadly accessible, furthering our commitment to helping network engineers build secure and reliable networks.
156156

_posts/2020-10-09-pre-deployment-validation-of-bgp-route-policies.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,22 @@ The _testRoutePolicies_ question enables you to test the behavior of a route pol
5151

5252
For example, to test the "_deny all incoming routes with private addresses_" intent you would run _testRoutePolicies_ on routes with prefixes in the private address space and check that all of them are denied.
5353

54-
Let’s take a look at an example route-policy from\_customer and evaluate its behavior with testRoutePolicies.
54+
Let’s take a look at an example route-policy from_customer and evaluate its behavior with testRoutePolicies.
5555

5656
```
57-
route-map from\_customer deny 100
57+
route-map from_customer deny 100
5858
match ip address prefix-list private-ips
5959
!
60-
route-map from\_customer permit 200
60+
route-map from_customer permit 200
6161
match ip address prefix-list from44
6262
match as-path origin44
6363
set community 20:30
6464
set local-preference 300
6565
!
66-
route-map from\_customer deny 300
66+
route-map from_customer deny 300
6767
match ip address prefix-list from44
6868
!
69-
route-map from\_customer permit 400
69+
route-map from_customer permit 400
7070
set community 20:30
7171
set local-preference 300
7272
@@ -76,19 +76,19 @@ ip prefix-list private-ips seq 15 permit 192.168.0.0/16
7676
!
7777
ip prefix-list from44 seq 10 permit 5.5.5.0/24 ge 24
7878
!
79-
ip as-path access-list origin44 permit \_44$
79+
ip as-path access-list origin44 permit _44$
8080
```
8181

8282
```
8383
inRoute1 = BgpRoute(network="10.0.0.0/24", originatorIp="4.4.4.4", originType="egp",protocol="bgp")
84-
result = bfq.testRoutePolicies(policies="from\_customer",direction="in",
84+
result = bfq.testRoutePolicies(policies="from_customer",direction="in",
8585
inputRoutes=\[inRoute1\]).answer().frame()
8686
print(result)
8787
88-
Node    Policy\_Name    Input\_Route Action Output\_Route Difference
88+
Node    Policy_Name    Input_Route Action Output_Route Difference
8989
90-
0  border1  from\_customer  BgpRoute(network='10.0.0.0/24', originatorIp='4.4.4.4', originType='egp', protocol='bgp', asPath=\[\], communities=\[\], localPreference=0, metric=0, sourceProtocol=None)  DENY   None         None
91-
1  border2  from\_customer  BgpRoute(network='10.0.0.0/24', originatorIp='4.4.4.4', originType='egp', protocol='bgp', asPath=\[\], communities=\[\], localPreference=0, metric=0, sourceProtocol=None)  DENY   None         None
90+
0  border1  from_customer  BgpRoute(network='10.0.0.0/24', originatorIp='4.4.4.4', originType='egp', protocol='bgp', asPath=\[\], communities=\[\], localPreference=0, metric=0, sourceProtocol=None)  DENY   None         None
91+
1  border2  from_customer  BgpRoute(network='10.0.0.0/24', originatorIp='4.4.4.4', originType='egp', protocol='bgp', asPath=\[\], communities=\[\], localPreference=0, metric=0, sourceProtocol=None)  DENY   None         None
9292
```
9393

9494
As you can see, Batfish correctly determines that the 10.0.0.0/24 route advertisement will get denied by the policy.
@@ -109,24 +109,24 @@ privateIps = \["10.0.0.0/8:8-32", "172.16.0.0/28:28-32", "192.168.0.0/16:16-32"\
109109
inRoutes1 = BgpRouteConstraints(prefix=privateIps)
110110
111111
\# Verify that no such announcement is permitted by our policy
112-
result = bfq.searchRoutePolicies(policies="from\_customer",
112+
result = bfq.searchRoutePolicies(policies="from_customer",
113113
inputConstraints=inRoutes1,
114114
action="permit").answer().frame()
115115
116116
print(result.loc\[0\])
117117
118118
Node border2
119-
Policy\_Name from\_customer
120-
Input\_Route BgpRoute(network='192.168.0.0/32', originatorIp='0.0.0.0', originType='igp', protocol='bgp', asPath=\[\], communities=\[\], localPreference=0, metric=0, sourceProtocol=None)
119+
Policy_Name from_customer
120+
Input_Route BgpRoute(network='192.168.0.0/32', originatorIp='0.0.0.0', originType='igp', protocol='bgp', asPath=\[\], communities=\[\], localPreference=0, metric=0, sourceProtocol=None)
121121
Action PERMIT
122-
Output\_Route BgpRoute(network='192.168.0.0/32', originatorIp='0.0.0.0', originType='igp', protocol='bgp', asPath=\[\], communities=\['20:30'\], localPreference=300, metric=0, sourceProtocol=None)
122+
Output_Route BgpRoute(network='192.168.0.0/32', originatorIp='0.0.0.0', originType='igp', protocol='bgp', asPath=\[\], communities=\['20:30'\], localPreference=300, metric=0, sourceProtocol=None)
123123
Difference BgpRouteDiffs(diffs=\[BgpRouteDiff(fieldName='communities', oldValue='\[\]', newValue='\[20:30\]'), BgpRouteDiff(fieldName='localPreference', oldValue='0', newValue='300')\])
124124
```
125125

126-
Batfish has found a route advertisement 192.168.0.0/32 that will be allowed by the routing policy, despite our intent being for it to be denied. There may be multiple route advertisements that violate our intent, Batfish picks one as an example to highlight the error. If you look closely at the routing policy, the route-map from\_customer is going to deny routes that match the prefix-list private-ips. The last entry in that prefix-list is incorrect. It is missing the "ge 16" option. As defined, that entry only matches the exact route 192.168.0.0/16, which means any other prefix from that 192.168.0.0/16 space will not be matched and therefore not be denied by the route-map.
126+
Batfish has found a route advertisement 192.168.0.0/32 that will be allowed by the routing policy, despite our intent being for it to be denied. There may be multiple route advertisements that violate our intent, Batfish picks one as an example to highlight the error. If you look closely at the routing policy, the route-map from_customer is going to deny routes that match the prefix-list private-ips. The last entry in that prefix-list is incorrect. It is missing the "ge 16" option. As defined, that entry only matches the exact route 192.168.0.0/16, which means any other prefix from that 192.168.0.0/16 space will not be matched and therefore not be denied by the route-map.
127127

128128
```
129-
route-map from\_customer deny 100 match ip address prefix-list private-ips
129+
route-map from_customer deny 100 match ip address prefix-list private-ips
130130
131131
ip prefix-list private-ips seq 5 permit 10.0.0.0/8 ge 8 ip prefix-list private-ips seq 10 permit 172.16.0.0/28 ge 28
132132
ip prefix-list private-ips seq 15 permit 192.168.0.0/16

_posts/2020-10-16-three-ways-to-break-a-network-and-one-to-save-it.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This category of bugs is as old as typewriters. Some entertaining examples off t
1414

1515
- Incorrectly assigned address (a public IP!) to a router interface: _100.x.y.z_ instead of _10.x.y.z_
1616
- Mistyped prefix list name: **prefix-list PFX-LIST 10.1O0.10.128/25** (the letter ‘O’ instead of the number ‘0’ in the prefix)
17-
- Mistyped access-list for a SNMP community: _SNMP-ACCESS-LIST_ instead of _SNMP\_ACCESS\_LIST_ (‘-’ vs ‘\_’)
17+
- Mistyped access-list for a SNMP community: _SNMP-ACCESS-LIST_ instead of _SNMP_ACCESS_LIST_ (‘-’ vs ‘\_’)
1818
- Mistyped route-map name: _BLEAD-TRAFFIC_ instead of _BLEED-TRAFFIC_
1919
- Mistyped keyword: **no bgp defaults ipv4-unicast** instead of **no bgp default ipv4-unicast**
2020
- Wrong BGP neighbor IP: **neighbor 169.254.127.3 activate** instead of **neighbor 169.54.127.1 activate**

_posts/2020-12-18-validating-the-validator.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ To appreciate the need to go beyond RFCs and docs, consider the following FRR co
2525
2 ip community-list 14 permit 65001:4
2626
3 ip community-list 24 permit 65002:4
2727
4 !
28-
5 route-map com\_update permit 10
28+
5 route-map com_update permit 10
2929
6 match community 14
3030
7 on-match goto 20
3131
8 set community 65002:4 additive
3232
9 !
33-
10 route-map com\_update permit 20
33+
10 route-map com_update permit 20
3434
11 match community 65002:4
3535
12 set community 65002:5 additive
3636
13 !
37-
14 route-map com\_update permit 30
37+
14 route-map com_update permit 30
3838
15 match community 24
3939
16 set community 65002:6 additive
4040
17 !

_posts/2021-05-18-automating-the-long-pole-of-network-changes.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ Let us illustrate how they work via an example: Allowing access to a new service
3939

4040
Your change generation script will use the request parameters to generate the configuration commands for one or more devices. For example, it may generate the following change to the Palo Alto firewall at the edge of the network:
4141

42-
set service S\_TCP\_80 protocol tcp port 80
43-
set service-group SG\_NEWSERVICE members S\_TCP\_80
44-
set service S\_TCP\_8080 protocol tcp port 8080
45-
set service-group SG\_NEWSERVICE members S\_TCP\_8080
42+
set service S_TCP_80 protocol tcp port 80
43+
set service-group SG_NEWSERVICE members S_TCP_80
44+
set service S_TCP_8080 protocol tcp port 8080
45+
set service-group SG_NEWSERVICE members S_TCP_8080
4646

4747
set address tkt123-dst1 ip-netmask 10.100.40.0/24
4848
set address-group tkt123-dst static tkt123-dst1
@@ -54,7 +54,7 @@ set rulebase security rules tkt123 to INSIDE
5454
set rulebase security rules tkt123 source any
5555
set rulebase security rules tkt123 destination tkt123-dst
5656
set rulebase security rules tkt123 application any
57-
set rulebase security rules tkt123 service SG\_NEWSERVICE
57+
set rulebase security rules tkt123 service SG_NEWSERVICE
5858
set rulebase security rules tkt123 action allow
5959

6060
This change may be generated using Jinja2 templates, an internal source-of-truth like Netbox, or the Palo Alto Ansible module. Regardless of how it is generated, you can submit it to Batfish Enterprise and analyze it using three criteria.

_posts/2021-05-26-closing-the-loop-on-testing-network-changes.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ The **.answer().frame()** part transforms the information returned by the questi
7575

7676
Suzieq’s Python interface is defined [here](https://suzieq.readthedocs.io/en/latest/developer/pythonAPI/). Suzieq organizes information in tables. For example, you can get the BGP table via:
7777

78-
bgp\_tbl = get\_sqobject(‘bgp)
78+
bgp_tbl = get_sqobject('bgp')
7979

8080
Every table contains a set of functions that return a Pandas DataFrame. Two common functions are get() and aver() (because assert is a Python keyword, Suzieq uses aver, an old synonym). Because Suzieq analyzes the operational state of the network, you must first gather this state by running the Suzieq poller for the devices of interest. [These instructions](https://suzieq.readthedocs.io/en/latest/poller/) will help you start the poller on your network.
8181

@@ -91,19 +91,19 @@ You can write Python programs that use the Batfish API to automate your pre-appr
9191

9292
![](/assets/images/fig-2.png){:width="800px"}
9393

94-
This program initializes the network snapshot (with planned config modifications) in **init\_bf()** and defines two tests. **test\_bgp\_status()** uses the **bgpSessionStatus** question to validate that all BGP sessions will be established after the change. **test\_all\_svi\_prefixes\_are\_on\_all\_leafs()** verifies that the SVI prefixes will be reachable on all nodes. It uses the **interfaceProperties** question to retrieve all SVI prefixes and verifies that each is reachable on all nodes. You retrieve the list of nodes using the **nodeProperties** question
94+
This program initializes the network snapshot (with planned config modifications) in **init_bf()** and defines two tests. **test_bgp_status()** uses the **bgpSessionStatus** question to validate that all BGP sessions will be established after the change. **test_all_svi_prefixes_are_on_all_leafs()** verifies that the SVI prefixes will be reachable on all nodes. It uses the **interfaceProperties** question to retrieve all SVI prefixes and verifies that each is reachable on all nodes. You retrieve the list of nodes using the **nodeProperties** question
9595

9696
**TIP:** The first time you use Batfish on your network, take a look at the output of **bfq.initIssues().answer().frame()** to confirm that Batfish understands it well. The output of this command is also a good thing to check when a test fails because problems such as syntax errors are also reported in it.
9797

9898
Hopefully, you now see the power of automated testing with tools like Batfish and Suzieq. A few lines of code can validate complex end-to-end behaviors across your entire network. When you add another leaf or spine, you can run this test suite as is. In fact, you can run the same test suite across different vendors. Our example network uses Arista EOS. You won’t have to change even a single line if it used Cisco or Juniper or Cumulus or a mix.
9999

100100
You can even use pytest, the Python testing framework, to run the tests and make full use of an advanced testing framework. If any of the assertions fail, pytest will report them, and you can investigate the error, fix the config change, and rerun the test suite.
101101

102-
Good testing tools also make it easy to debug test failures. How you do that depends on the test. For example, if we had assigned an incorrect interface IP address on the new leaf, **test\_bgp\_status()** would fail because not all sessions would be in **ESTABLISHED** state. You may then look at the output of **bgpSessionStatus** question, which for this example will show that the sessions on leaf03 and spine01 are incompatible. To understand why, you may then run the **bgpSessionCompatibility** question as follows.
102+
Good testing tools also make it easy to debug test failures. How you do that depends on the test. For example, if we had assigned an incorrect interface IP address on the new leaf, **test_bgp_status()** would fail because not all sessions would be in **ESTABLISHED** state. You may then look at the output of **bgpSessionStatus** question, which for this example will show that the sessions on leaf03 and spine01 are incompatible. To understand why, you may then run the **bgpSessionCompatibility** question as follows.
103103

104104
![](/assets/images/fig-3.png){:width="1000px"}
105105

106-
This output tells you that you likely have the wrong IP address on leaf03 (**NO\_LOCAL\_IP**), and that spine01 expects to establish a session to 10.127.0.5 but no such IP is present in the snapshot (**UNKNOWN\_REMOTE**). If you fix the configs, and rerun the tests,  they should all pass now, and you can be confident that your change is ready to be scheduled for deployment.
106+
This output tells you that you likely have the wrong IP address on leaf03 (**NO_LOCAL_IP**), and that spine01 expects to establish a session to 10.127.0.5 but no such IP is present in the snapshot (**UNKNOWN_REMOTE**). If you fix the configs, and rerun the tests,  they should all pass now, and you can be confident that your change is ready to be scheduled for deployment.
107107

108108
#### Deployment pre-testing
109109

@@ -117,9 +117,9 @@ As in the case of Batfish, your automated test suite will be a Python program. T
117117

118118
![](/assets/images/fig-4.png){:width="800px"}
119119

120-
Each test uses **get\_sqobject()** to get the relevant tables, then uses the get function to retrieve the rows and columns of interest, and finally checks that a specific column has an expected value on all nodes. The **.all()** checks that the field has that value on all rows of the retrieved dataset. Thus, the test to check that all spines are alive uses the “device” table to retrieve information about the spines, and checks that the “status” column has the value “alive” in all rows. **test\_spine\_port\_is\_free()** assumes that the spine ports have been cabled up and uses the lack of an LLDP peer to confirm that the port connecting to the new leaf is unused
120+
Each test uses **get_sqobject()** to get the relevant tables, then uses the get function to retrieve the rows and columns of interest, and finally checks that a specific column has an expected value on all nodes. The **.all()** checks that the field has that value on all rows of the retrieved dataset. Thus, the test to check that all spines are alive uses the “device” table to retrieve information about the spines, and checks that the “status” column has the value “alive” in all rows. **test_spine_port_is_free()** assumes that the spine ports have been cabled up and uses the lack of an LLDP peer to confirm that the port connecting to the new leaf is unused
121121

122-
Like Batfish, this code is vendor-agnostic and works for any Suzieq-supported vendor. If you add additional leafs, you just need to change the values of SPINE\_IFNAME and NEW\_SVI\_PREFIX. This is the power of writing tests using frameworks like Suzieq.
122+
Like Batfish, this code is vendor-agnostic and works for any Suzieq-supported vendor. If you add additional leafs, you just need to change the values of SPINE_IFNAME and NEW_SVI_PREFIX. This is the power of writing tests using frameworks like Suzieq.
123123

124124
If all deployment pre-tests pass, you can confidently deploy the change. But before you declare victory, you still need to test that the deployment went as planned. So, let's do that next.
125125

0 commit comments

Comments
 (0)